Some refactor and fix warnings
This commit is contained in:
1111
docs/parser_classes.gaphor
Normal file
1111
docs/parser_classes.gaphor
Normal file
File diff suppressed because it is too large
Load Diff
BIN
docs/parser_classes.png
Normal file
BIN
docs/parser_classes.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 53 KiB |
@@ -28,6 +28,13 @@ public interface MangaParser : Interceptor {
|
|||||||
|
|
||||||
public val config: MangaSourceConfig
|
public val config: MangaSourceConfig
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Provide default domain and available alternatives, if any.
|
||||||
|
*
|
||||||
|
* Never hardcode domain in requests, use [domain] instead.
|
||||||
|
*/
|
||||||
|
public val configKeyDomain: ConfigKey.Domain
|
||||||
|
|
||||||
public val domain: String
|
public val domain: String
|
||||||
|
|
||||||
public suspend fun getList(query: MangaSearchQuery): List<Manga>
|
public suspend fun getList(query: MangaSearchQuery): List<Manga>
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import java.util.*
|
|||||||
@InternalParsersApi
|
@InternalParsersApi
|
||||||
public abstract class AbstractMangaParser @InternalParsersApi constructor(
|
public abstract class AbstractMangaParser @InternalParsersApi constructor(
|
||||||
@property:InternalParsersApi public val context: MangaLoaderContext,
|
@property:InternalParsersApi public val context: MangaLoaderContext,
|
||||||
public override val source: MangaParserSource,
|
public final override val source: MangaParserSource,
|
||||||
) : MangaParser {
|
) : MangaParser {
|
||||||
|
|
||||||
public override val config: MangaSourceConfig by lazy { context.getConfig(source) }
|
public override val config: MangaSourceConfig by lazy { context.getConfig(source) }
|
||||||
@@ -30,16 +30,18 @@ public abstract class AbstractMangaParser @InternalParsersApi constructor(
|
|||||||
public open val sourceLocale: Locale
|
public open val sourceLocale: Locale
|
||||||
get() = if (source.locale.isEmpty()) Locale.ROOT else Locale(source.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())
|
protected open val userAgentKey: ConfigKey.UserAgent = ConfigKey.UserAgent(context.getDefaultUserAgent())
|
||||||
|
|
||||||
|
protected val sourceContentRating: ContentRating?
|
||||||
|
get() = if (source.contentType == ContentType.HENTAI) {
|
||||||
|
ContentRating.ADULT
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
final override val domain: String
|
||||||
|
get() = config[configKeyDomain]
|
||||||
|
|
||||||
@Deprecated("Override intercept() instead")
|
@Deprecated("Override intercept() instead")
|
||||||
override fun getRequestHeaders(): Headers = Headers.Builder()
|
override fun getRequestHeaders(): Headers = Headers.Builder()
|
||||||
.add("User-Agent", config[userAgentKey])
|
.add("User-Agent", config[userAgentKey])
|
||||||
@@ -54,9 +56,6 @@ public abstract class AbstractMangaParser @InternalParsersApi constructor(
|
|||||||
return SortOrder.entries.first { it in supported }
|
return SortOrder.entries.first { it in supported }
|
||||||
}
|
}
|
||||||
|
|
||||||
override val domain: String
|
|
||||||
get() = config[configKeyDomain]
|
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
protected val webClient: WebClient = OkHttpWebClient(context.httpClient, source)
|
protected val webClient: WebClient = OkHttpWebClient(context.httpClient, source)
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import java.util.*
|
|||||||
@InternalParsersApi
|
@InternalParsersApi
|
||||||
public abstract class LegacyMangaParser @InternalParsersApi constructor(
|
public abstract class LegacyMangaParser @InternalParsersApi constructor(
|
||||||
@property:InternalParsersApi public val context: MangaLoaderContext,
|
@property:InternalParsersApi public val context: MangaLoaderContext,
|
||||||
public override val source: MangaParserSource,
|
public final override val source: MangaParserSource,
|
||||||
) : MangaParser {
|
) : MangaParser {
|
||||||
|
|
||||||
public final override val searchQueryCapabilities: MangaSearchQueryCapabilities
|
public final override val searchQueryCapabilities: MangaSearchQueryCapabilities
|
||||||
@@ -37,14 +37,6 @@ public abstract class LegacyMangaParser @InternalParsersApi constructor(
|
|||||||
|
|
||||||
protected val isNsfwSource: Boolean = source.contentType == ContentType.HENTAI
|
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())
|
protected open val userAgentKey: ConfigKey.UserAgent = ConfigKey.UserAgent(context.getDefaultUserAgent())
|
||||||
|
|
||||||
override fun getRequestHeaders(): Headers = Headers.Builder()
|
override fun getRequestHeaders(): Headers = Headers.Builder()
|
||||||
@@ -60,7 +52,7 @@ public abstract class LegacyMangaParser @InternalParsersApi constructor(
|
|||||||
return SortOrder.entries.first { it in supported }
|
return SortOrder.entries.first { it in supported }
|
||||||
}
|
}
|
||||||
|
|
||||||
override val domain: String
|
final override val domain: String
|
||||||
get() = config[configKeyDomain]
|
get() = config[configKeyDomain]
|
||||||
|
|
||||||
@JvmField
|
@JvmField
|
||||||
|
|||||||
@@ -14,11 +14,11 @@ internal class MangaParserWrapper(
|
|||||||
private val delegate: MangaParser,
|
private val delegate: MangaParser,
|
||||||
) : MangaParser by delegate {
|
) : MangaParser by delegate {
|
||||||
|
|
||||||
override suspend fun getList(searchQuery: MangaSearchQuery): List<Manga> = withContext(Dispatchers.Default) {
|
override suspend fun getList(query: MangaSearchQuery): List<Manga> = withContext(Dispatchers.Default) {
|
||||||
if (!searchQuery.skipValidation) {
|
if (!query.skipValidation) {
|
||||||
searchQueryCapabilities.validate(searchQuery)
|
searchQueryCapabilities.validate(query)
|
||||||
}
|
}
|
||||||
delegate.getList(searchQuery)
|
delegate.getList(query)
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun getDetails(manga: Manga): Manga = withContext(Dispatchers.Default) {
|
override suspend fun getDetails(manga: Manga): Manga = withContext(Dispatchers.Default) {
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ internal abstract class MangaboxParser(
|
|||||||
authors = emptySet(),
|
authors = emptySet(),
|
||||||
state = null,
|
state = null,
|
||||||
source = source,
|
source = source,
|
||||||
contentRating = if (source.contentType == ContentType.HENTAI) ContentRating.ADULT else ContentRating.SAFE,
|
contentRating = sourceContentRating,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -29,7 +29,7 @@ internal class ManhwaIndoParser(context: MangaLoaderContext) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun fetchPage(img: Element): MangaPage? = runCatchingCancellable {
|
private suspend fun fetchPage(img: Element): MangaPage? = runCatchingCancellable {
|
||||||
val url = img.requireSrc().toAbsoluteUrl(domain) ?: return@runCatchingCancellable null
|
val url = img.requireSrc().toAbsoluteUrl(domain)
|
||||||
webClient.httpHead(url).use { response ->
|
webClient.httpHead(url).use { response ->
|
||||||
if (response.mimeType?.startsWith("image/") == true) {
|
if (response.mimeType?.startsWith("image/") == true) {
|
||||||
MangaPage(
|
MangaPage(
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ internal class Hentai18VN(context: MangaLoaderContext) :
|
|||||||
parseMangaSearch(response)
|
parseMangaSearch(response)
|
||||||
}
|
}
|
||||||
|
|
||||||
!filter.tags.isNullOrEmpty() -> {
|
filter.tags.isNotEmpty() -> {
|
||||||
val tag = filter.tags.first()
|
val tag = filter.tags.first()
|
||||||
val url = buildString {
|
val url = buildString {
|
||||||
append("https://")
|
append("https://")
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ internal class HentaiVnBuzz(context: MangaLoaderContext) :
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
!filter.tags.isNullOrEmpty() -> {
|
filter.tags.isNotEmpty() -> {
|
||||||
val tag = filter.tags.first()
|
val tag = filter.tags.first()
|
||||||
buildString {
|
buildString {
|
||||||
append("/the-loai/")
|
append("/the-loai/")
|
||||||
@@ -110,7 +110,7 @@ internal class HentaiVnBuzz(context: MangaLoaderContext) :
|
|||||||
val doc = webClient.httpGet(fullUrl).parseHtml()
|
val doc = webClient.httpGet(fullUrl).parseHtml()
|
||||||
return when {
|
return when {
|
||||||
!filter.query.isNullOrEmpty() -> parseSearchManga(doc)
|
!filter.query.isNullOrEmpty() -> parseSearchManga(doc)
|
||||||
!filter.tags.isNullOrEmpty() -> parseSearchManga(doc)
|
filter.tags.isNotEmpty() -> parseSearchManga(doc)
|
||||||
else -> parseListManga(doc)
|
else -> parseListManga(doc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ internal class TruyenHentaiVN(context: MangaLoaderContext) :
|
|||||||
append(domain)
|
append(domain)
|
||||||
|
|
||||||
when {
|
when {
|
||||||
!filter.tags.isNullOrEmpty() -> {
|
filter.tags.isNotEmpty() -> {
|
||||||
val tag = filter.tags.first()
|
val tag = filter.tags.first()
|
||||||
append(tag.key)
|
append(tag.key)
|
||||||
if (page > 1) {
|
if (page > 1) {
|
||||||
|
|||||||
@@ -222,7 +222,7 @@ internal class DocTruyen3Q(context: MangaLoaderContext) :
|
|||||||
val fullUrl = chapter.url.toAbsoluteUrl(domain)
|
val fullUrl = chapter.url.toAbsoluteUrl(domain)
|
||||||
val doc = webClient.httpGet(fullUrl).parseHtml()
|
val doc = webClient.httpGet(fullUrl).parseHtml()
|
||||||
return doc.select("div.page-chapter img").mapNotNull { img ->
|
return doc.select("div.page-chapter img").mapNotNull { img ->
|
||||||
val url = img.attr("src")?.toAbsoluteUrl(domain) ?: return@mapNotNull null
|
val url = img.attrAsAbsoluteUrlOrNull("src") ?: return@mapNotNull null
|
||||||
MangaPage(
|
MangaPage(
|
||||||
id = generateUid(url),
|
id = generateUid(url),
|
||||||
url = url,
|
url = url,
|
||||||
|
|||||||
@@ -3,19 +3,18 @@ package org.koitharu.kotatsu.parsers.site.wpcomics.vi
|
|||||||
import androidx.collection.ArraySet
|
import androidx.collection.ArraySet
|
||||||
import kotlinx.coroutines.async
|
import kotlinx.coroutines.async
|
||||||
import kotlinx.coroutines.coroutineScope
|
import kotlinx.coroutines.coroutineScope
|
||||||
import org.jsoup.nodes.Document
|
|
||||||
import org.koitharu.kotatsu.parsers.model.*
|
|
||||||
import org.koitharu.kotatsu.parsers.util.*
|
|
||||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||||
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
import org.koitharu.kotatsu.parsers.MangaSourceParser
|
||||||
import org.koitharu.kotatsu.parsers.site.wpcomics.WpComicsParser
|
|
||||||
import org.koitharu.kotatsu.parsers.exception.ParseException
|
import org.koitharu.kotatsu.parsers.exception.ParseException
|
||||||
|
import org.koitharu.kotatsu.parsers.model.*
|
||||||
|
import org.koitharu.kotatsu.parsers.site.wpcomics.WpComicsParser
|
||||||
|
import org.koitharu.kotatsu.parsers.util.*
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@MangaSourceParser("NEWTRUYEN", "NewTruyen", "vi")
|
@MangaSourceParser("NEWTRUYEN", "NewTruyen", "vi")
|
||||||
internal class NewTruyen(context: MangaLoaderContext) :
|
internal class NewTruyen(context: MangaLoaderContext) :
|
||||||
WpComicsParser(context, MangaParserSource.NEWTRUYEN, "newtruyen2.com", 36) {
|
WpComicsParser(context, MangaParserSource.NEWTRUYEN, "newtruyen2.com", 36) {
|
||||||
|
|
||||||
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
override suspend fun getFilterOptions() = MangaListFilterOptions(
|
||||||
availableTags = getAvailableTags(),
|
availableTags = getAvailableTags(),
|
||||||
@@ -26,14 +25,14 @@ internal class NewTruyen(context: MangaLoaderContext) :
|
|||||||
val fullUrl = manga.url.toAbsoluteUrl(domain)
|
val fullUrl = manga.url.toAbsoluteUrl(domain)
|
||||||
val doc = webClient.httpGet(fullUrl).parseHtml()
|
val doc = webClient.httpGet(fullUrl).parseHtml()
|
||||||
val storyID = doc.selectFirst("input#storyID")?.attr("value")
|
val storyID = doc.selectFirst("input#storyID")?.attr("value")
|
||||||
?: throw ParseException("Story ID not found", fullUrl)
|
?: throw ParseException("Story ID not found", fullUrl)
|
||||||
val chaptersDeferred = async { getChapterList(storyID) }
|
val chaptersDeferred = async { getChapterList(storyID) }
|
||||||
val tagsElement = doc.select("p.col-xs-12 a.tr-theloai")
|
val tagsElement = doc.select("p.col-xs-12 a.tr-theloai")
|
||||||
val mangaTags = tagsElement.map {
|
val mangaTags = tagsElement.map {
|
||||||
MangaTag(
|
MangaTag(
|
||||||
title = it.text(),
|
title = it.text(),
|
||||||
key = it.attr("href").substringAfterLast('/'),
|
key = it.attr("href").substringAfterLast('/'),
|
||||||
source = source
|
source = source,
|
||||||
)
|
)
|
||||||
}.toSet()
|
}.toSet()
|
||||||
val author = doc.body().select(selectAut).textOrNull()
|
val author = doc.body().select(selectAut).textOrNull()
|
||||||
@@ -54,7 +53,7 @@ internal class NewTruyen(context: MangaLoaderContext) :
|
|||||||
}
|
}
|
||||||
|
|
||||||
private suspend fun getChapterList(storyID: String): List<MangaChapter> {
|
private suspend fun getChapterList(storyID: String): List<MangaChapter> {
|
||||||
val url = "/Story/ListChapterByStoryID?storyID=" + storyID
|
val url = "/Story/ListChapterByStoryID?storyID=$storyID"
|
||||||
val fullUrl = url.toAbsoluteUrl(domain)
|
val fullUrl = url.toAbsoluteUrl(domain)
|
||||||
val doc = webClient.httpGet(fullUrl).parseHtml()
|
val doc = webClient.httpGet(fullUrl).parseHtml()
|
||||||
return doc.select("div.col-xs-5.chapter").mapChapters(reversed = true) { i, li ->
|
return doc.select("div.col-xs-5.chapter").mapChapters(reversed = true) { i, li ->
|
||||||
|
|||||||
@@ -87,3 +87,15 @@ public inline fun <T, reified R> Collection<T>.mapToArray(transform: (T) -> R):
|
|||||||
forEachIndexed { index, t -> result[index] = transform(t) }
|
forEachIndexed { index, t -> result[index] = transform(t) }
|
||||||
return result as Array<R>
|
return result as Array<R>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun <T> Array<T>.toArraySet(): Set<T> = when (size) {
|
||||||
|
0 -> emptySet()
|
||||||
|
1 -> setOf(first())
|
||||||
|
else -> ArraySet(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun <T> Collection<T>.toArraySet(): Set<T> = when (size) {
|
||||||
|
0 -> emptySet()
|
||||||
|
1 -> setOf(first())
|
||||||
|
else -> ArraySet(this)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user