Change configuration behavior
This commit is contained in:
@@ -5,6 +5,7 @@ import okhttp3.MediaType.Companion.toMediaType
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import org.json.JSONObject
|
||||
import org.jsoup.HttpStatusException
|
||||
import org.koitharu.kotatsu.parsers.config.MangaSourceConfig
|
||||
import org.koitharu.kotatsu.parsers.exception.GraphQLException
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.util.await
|
||||
|
||||
@@ -1,19 +1,18 @@
|
||||
package org.koitharu.kotatsu.parsers
|
||||
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.exception.ParseException
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
|
||||
abstract class MangaParser {
|
||||
abstract class MangaParser(val source: MangaSource) {
|
||||
|
||||
protected abstract val context: MangaLoaderContext
|
||||
|
||||
abstract val source: MangaSource
|
||||
|
||||
abstract val sortOrders: Set<SortOrder>
|
||||
|
||||
abstract val defaultDomain: String
|
||||
val config by lazy { context.getConfig(source) }
|
||||
|
||||
protected val config by lazy { context.getConfig(source) }
|
||||
protected abstract val configKeyDomain: ConfigKey.Domain
|
||||
|
||||
abstract suspend fun getList(
|
||||
offset: Int,
|
||||
@@ -32,10 +31,14 @@ abstract class MangaParser {
|
||||
|
||||
open fun getFaviconUrl() = "https://${getDomain()}/favicon.ico"
|
||||
|
||||
open fun onCreateConfig(keys: MutableCollection<ConfigKey<*>>) {
|
||||
keys.add(configKeyDomain)
|
||||
}
|
||||
|
||||
/* Utils */
|
||||
|
||||
protected fun getDomain(): String {
|
||||
return config.getDomain(defaultDomain)
|
||||
fun getDomain(): String {
|
||||
return config[configKeyDomain]
|
||||
}
|
||||
|
||||
protected fun generateUid(url: String): Long {
|
||||
@@ -60,25 +63,19 @@ abstract class MangaParser {
|
||||
|
||||
protected fun String.withDomain(subdomain: String? = null) = when {
|
||||
this.startsWith("//") -> buildString {
|
||||
append("http")
|
||||
if (config.isSslEnabled(true)) {
|
||||
append('s')
|
||||
}
|
||||
append("https")
|
||||
append(":")
|
||||
append(this@withDomain)
|
||||
}
|
||||
this.startsWith("/") -> buildString {
|
||||
append("http")
|
||||
if (config.isSslEnabled(true)) {
|
||||
append('s')
|
||||
}
|
||||
append("https")
|
||||
append("://")
|
||||
if (subdomain != null) {
|
||||
append(subdomain)
|
||||
append('.')
|
||||
append(config.getDomain(defaultDomain).removePrefix("www."))
|
||||
append(getDomain().removePrefix("www."))
|
||||
} else {
|
||||
append(config.getDomain(defaultDomain))
|
||||
append(getDomain())
|
||||
}
|
||||
append(this@withDomain)
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
package org.koitharu.kotatsu.parsers
|
||||
|
||||
interface MangaSourceConfig {
|
||||
fun getDomain(defaultValue: String): String
|
||||
fun isSslEnabled(defaultValue: Boolean): Boolean
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package org.koitharu.kotatsu.parsers.config
|
||||
|
||||
sealed class ConfigKey<T>(
|
||||
val key: String,
|
||||
) {
|
||||
|
||||
abstract val defaultValue: T
|
||||
|
||||
class Domain(
|
||||
override val defaultValue: String,
|
||||
val presetValues: Array<String>?,
|
||||
) : ConfigKey<String>("domain")
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package org.koitharu.kotatsu.parsers.config
|
||||
|
||||
interface MangaSourceConfig {
|
||||
|
||||
operator fun <T> get(key: ConfigKey<T>): T
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
package org.koitharu.kotatsu.parsers.model
|
||||
|
||||
internal const val RATING_UNKNOWN = -1f
|
||||
@@ -1,25 +1,98 @@
|
||||
package org.koitharu.kotatsu.parsers.model
|
||||
|
||||
data class Manga(
|
||||
class Manga(
|
||||
val id: Long,
|
||||
val title: String,
|
||||
val altTitle: String? = null,
|
||||
val altTitle: String?,
|
||||
val url: String, // relative url for internal use
|
||||
val publicUrl: String,
|
||||
val rating: Float = NO_RATING, // normalized value [0..1] or -1
|
||||
val isNsfw: Boolean = false,
|
||||
val rating: Float, // normalized value [0..1] or -1
|
||||
val isNsfw: Boolean,
|
||||
val coverUrl: String,
|
||||
val tags: Set<MangaTag>,
|
||||
val state: MangaState?,
|
||||
val author: String?,
|
||||
val largeCoverUrl: String? = null,
|
||||
val description: String? = null, // HTML
|
||||
val tags: Set<MangaTag> = emptySet(),
|
||||
val state: MangaState? = null,
|
||||
val author: String? = null,
|
||||
val chapters: List<MangaChapter>? = null,
|
||||
val source: MangaSource,
|
||||
) {
|
||||
|
||||
companion object {
|
||||
val hasRating: Boolean
|
||||
get() = rating in 0f..1f
|
||||
|
||||
const val NO_RATING = -1f
|
||||
internal fun copy(
|
||||
title: String = this.title,
|
||||
altTitle: String? = this.altTitle,
|
||||
publicUrl: String = this.publicUrl,
|
||||
rating: Float = this.rating,
|
||||
isNsfw: Boolean = this.isNsfw,
|
||||
coverUrl: String = this.coverUrl,
|
||||
tags: Set<MangaTag> = this.tags,
|
||||
state: MangaState? = this.state,
|
||||
author: String? = this.author,
|
||||
largeCoverUrl: String? = this.largeCoverUrl,
|
||||
description: String? = this.description,
|
||||
chapters: List<MangaChapter>? = this.chapters,
|
||||
) = Manga(
|
||||
id = id,
|
||||
title = title,
|
||||
altTitle = altTitle,
|
||||
url = url,
|
||||
publicUrl = publicUrl,
|
||||
rating = rating,
|
||||
isNsfw = isNsfw,
|
||||
coverUrl = coverUrl,
|
||||
tags = tags,
|
||||
state = state,
|
||||
author = author,
|
||||
largeCoverUrl = largeCoverUrl,
|
||||
description = description,
|
||||
chapters = chapters,
|
||||
source = source,
|
||||
)
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as Manga
|
||||
|
||||
if (id != other.id) return false
|
||||
if (title != other.title) return false
|
||||
if (altTitle != other.altTitle) return false
|
||||
if (url != other.url) return false
|
||||
if (publicUrl != other.publicUrl) return false
|
||||
if (rating != other.rating) return false
|
||||
if (isNsfw != other.isNsfw) return false
|
||||
if (coverUrl != other.coverUrl) return false
|
||||
if (tags != other.tags) return false
|
||||
if (state != other.state) return false
|
||||
if (author != other.author) return false
|
||||
if (largeCoverUrl != other.largeCoverUrl) return false
|
||||
if (description != other.description) return false
|
||||
if (chapters != other.chapters) return false
|
||||
if (source != other.source) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = id.hashCode()
|
||||
result = 31 * result + title.hashCode()
|
||||
result = 31 * result + (altTitle?.hashCode() ?: 0)
|
||||
result = 31 * result + url.hashCode()
|
||||
result = 31 * result + publicUrl.hashCode()
|
||||
result = 31 * result + rating.hashCode()
|
||||
result = 31 * result + isNsfw.hashCode()
|
||||
result = 31 * result + coverUrl.hashCode()
|
||||
result = 31 * result + tags.hashCode()
|
||||
result = 31 * result + (state?.hashCode() ?: 0)
|
||||
result = 31 * result + (author?.hashCode() ?: 0)
|
||||
result = 31 * result + (largeCoverUrl?.hashCode() ?: 0)
|
||||
result = 31 * result + (description?.hashCode() ?: 0)
|
||||
result = 31 * result + (chapters?.hashCode() ?: 0)
|
||||
result = 31 * result + source.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package org.koitharu.kotatsu.parsers.model
|
||||
|
||||
data class MangaChapter(
|
||||
class MangaChapter(
|
||||
val id: Long,
|
||||
val name: String,
|
||||
val number: Int,
|
||||
@@ -14,4 +14,36 @@ data class MangaChapter(
|
||||
override fun compareTo(other: MangaChapter): Int {
|
||||
return number.compareTo(other.number)
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as MangaChapter
|
||||
|
||||
if (id != other.id) return false
|
||||
if (name != other.name) return false
|
||||
if (number != other.number) return false
|
||||
if (url != other.url) return false
|
||||
if (scanlator != other.scanlator) return false
|
||||
if (uploadDate != other.uploadDate) return false
|
||||
if (branch != other.branch) return false
|
||||
if (source != other.source) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = id.hashCode()
|
||||
result = 31 * result + name.hashCode()
|
||||
result = 31 * result + number
|
||||
result = 31 * result + url.hashCode()
|
||||
result = 31 * result + (scanlator?.hashCode() ?: 0)
|
||||
result = 31 * result + uploadDate.hashCode()
|
||||
result = 31 * result + (branch?.hashCode() ?: 0)
|
||||
result = 31 * result + source.hashCode()
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,9 +1,34 @@
|
||||
package org.koitharu.kotatsu.parsers.model
|
||||
|
||||
data class MangaPage(
|
||||
class MangaPage(
|
||||
val id: Long,
|
||||
val url: String,
|
||||
val referer: String,
|
||||
val preview: String?,
|
||||
val source: MangaSource,
|
||||
)
|
||||
) {
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as MangaPage
|
||||
|
||||
if (id != other.id) return false
|
||||
if (url != other.url) return false
|
||||
if (referer != other.referer) return false
|
||||
if (preview != other.preview) return false
|
||||
if (source != other.source) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = id.hashCode()
|
||||
result = 31 * result + url.hashCode()
|
||||
result = 31 * result + referer.hashCode()
|
||||
result = 31 * result + (preview?.hashCode() ?: 0)
|
||||
result = 31 * result + source.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,28 @@
|
||||
package org.koitharu.kotatsu.parsers.model
|
||||
|
||||
data class MangaTag(
|
||||
class MangaTag(
|
||||
val title: String,
|
||||
val key: String,
|
||||
val source: MangaSource,
|
||||
)
|
||||
) {
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (this === other) return true
|
||||
if (javaClass != other?.javaClass) return false
|
||||
|
||||
other as MangaTag
|
||||
|
||||
if (title != other.title) return false
|
||||
if (key != other.key) return false
|
||||
if (source != other.source) return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun hashCode(): Int {
|
||||
var result = title.hashCode()
|
||||
result = 31 * result + key.hashCode()
|
||||
result = 31 * result + source.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
@@ -5,17 +5,16 @@ import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaParser
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.util.json.mapJSON
|
||||
import org.koitharu.kotatsu.parsers.util.json.mapJSONIndexed
|
||||
import org.koitharu.kotatsu.parsers.util.json.stringIterator
|
||||
import java.util.*
|
||||
|
||||
internal class AnibelParser(override val context: MangaLoaderContext) : MangaParser() {
|
||||
internal class AnibelParser(override val context: MangaLoaderContext) : MangaParser(MangaSource.ANIBEL) {
|
||||
|
||||
override val source = MangaSource.ANIBEL
|
||||
|
||||
override val defaultDomain = "anibel.net"
|
||||
override val configKeyDomain = ConfigKey.Domain("anibel.net", null)
|
||||
|
||||
override val sortOrders: Set<SortOrder> = EnumSet.of(
|
||||
SortOrder.NEWEST,
|
||||
@@ -73,6 +72,7 @@ internal class AnibelParser(override val context: MangaLoaderContext) : MangaPar
|
||||
.withDomain("cdn") + "?width=200&height=280",
|
||||
altTitle = title.getString("alt").takeUnless(String::isEmpty),
|
||||
author = null,
|
||||
isNsfw = false,
|
||||
rating = jo.getDouble("rating").toFloat() / 10f,
|
||||
url = href,
|
||||
publicUrl = "https://${getDomain()}/$href",
|
||||
@@ -213,7 +213,8 @@ internal class AnibelParser(override val context: MangaLoaderContext) : MangaPar
|
||||
.withDomain("cdn") + "?width=200&height=280",
|
||||
altTitle = title.getString("en").takeUnless(String::isEmpty),
|
||||
author = null,
|
||||
rating = Manga.NO_RATING,
|
||||
isNsfw = false,
|
||||
rating = RATING_UNKNOWN,
|
||||
url = href,
|
||||
publicUrl = "https://${getDomain()}/$href",
|
||||
tags = emptySet(),
|
||||
|
||||
@@ -6,6 +6,7 @@ import org.json.JSONObject
|
||||
import org.jsoup.nodes.Element
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaParser
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
import java.nio.charset.StandardCharsets
|
||||
@@ -18,9 +19,7 @@ import javax.crypto.spec.SecretKeySpec
|
||||
private const val PAGE_SIZE = 60
|
||||
private const val PAGE_SIZE_SEARCH = 20
|
||||
|
||||
internal class BatoToParser(override val context: MangaLoaderContext) : MangaParser() {
|
||||
|
||||
override val source = MangaSource.BATOTO
|
||||
internal class BatoToParser(override val context: MangaLoaderContext) : MangaParser(MangaSource.BATOTO) {
|
||||
|
||||
override val sortOrders: Set<SortOrder> = EnumSet.of(
|
||||
SortOrder.NEWEST,
|
||||
@@ -29,7 +28,10 @@ internal class BatoToParser(override val context: MangaLoaderContext) : MangaPar
|
||||
SortOrder.ALPHABETICAL,
|
||||
)
|
||||
|
||||
override val defaultDomain: String = "bato.to"
|
||||
override val configKeyDomain = ConfigKey.Domain(
|
||||
"bato.to",
|
||||
arrayOf("bato.to", "mto.to", "mangatoto.com", "battwo.com", "batotwo.com", "comiko.net", "batotoo.com"),
|
||||
)
|
||||
|
||||
override suspend fun getList(
|
||||
offset: Int,
|
||||
@@ -193,7 +195,7 @@ internal class BatoToParser(override val context: MangaLoaderContext) : MangaPar
|
||||
altTitle = div.selectFirst(".item-alias")?.text()?.takeUnless { it == title },
|
||||
url = href,
|
||||
publicUrl = a.absUrl("href"),
|
||||
rating = Manga.NO_RATING,
|
||||
rating = RATING_UNKNOWN,
|
||||
isNsfw = false,
|
||||
coverUrl = div.selectFirst("img[src]")?.absUrl("src").orEmpty(),
|
||||
largeCoverUrl = null,
|
||||
|
||||
@@ -7,7 +7,7 @@ import org.koitharu.kotatsu.parsers.util.*
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
internal abstract class ChanParser : MangaParser() {
|
||||
internal abstract class ChanParser(source: MangaSource) : MangaParser(source) {
|
||||
|
||||
override val sortOrders: Set<SortOrder> = EnumSet.of(
|
||||
SortOrder.NEWEST,
|
||||
@@ -64,6 +64,9 @@ internal abstract class ChanParser : MangaParser() {
|
||||
)
|
||||
}
|
||||
}.getOrNull().orEmpty(),
|
||||
rating = RATING_UNKNOWN,
|
||||
state = null,
|
||||
isNsfw = false,
|
||||
source = source,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@ import org.json.JSONArray
|
||||
import org.json.JSONObject
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaParser
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
import org.koitharu.kotatsu.parsers.util.json.JSONIterator
|
||||
@@ -22,10 +23,10 @@ import java.util.*
|
||||
private const val PAGE_SIZE = 20
|
||||
private const val CHAPTERS_LIMIT = 99999
|
||||
|
||||
internal class ComickFunParser(override val context: MangaLoaderContext) : MangaParser() {
|
||||
internal class ComickFunParser(override val context: MangaLoaderContext) : MangaParser(MangaSource.COMICK_FUN) {
|
||||
|
||||
override val configKeyDomain = ConfigKey.Domain("comick.fun", null)
|
||||
|
||||
override val defaultDomain = "comick.fun"
|
||||
override val source = MangaSource.COMICK_FUN
|
||||
override val sortOrders: Set<SortOrder> = EnumSet.of(
|
||||
SortOrder.POPULARITY,
|
||||
SortOrder.UPDATED,
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.parsers.site
|
||||
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaParser
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.exception.ParseException
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
@@ -10,11 +11,9 @@ import org.koitharu.kotatsu.parsers.util.json.mapJSONIndexed
|
||||
import org.koitharu.kotatsu.parsers.util.json.mapJSONToSet
|
||||
import java.util.*
|
||||
|
||||
internal class DesuMeParser(override val context: MangaLoaderContext) : MangaParser() {
|
||||
internal class DesuMeParser(override val context: MangaLoaderContext) : MangaParser(MangaSource.DESUME) {
|
||||
|
||||
override val source = MangaSource.DESUME
|
||||
|
||||
override val defaultDomain = "desu.me"
|
||||
override val configKeyDomain = ConfigKey.Domain("desu.me", null)
|
||||
|
||||
override val sortOrders: Set<SortOrder> = EnumSet.of(
|
||||
SortOrder.UPDATED,
|
||||
@@ -71,6 +70,9 @@ internal class DesuMeParser(override val context: MangaLoaderContext) : MangaPar
|
||||
},
|
||||
rating = jo.getDouble("score").toFloat().coerceIn(0f, 1f),
|
||||
id = generateUid(id),
|
||||
isNsfw = false,
|
||||
tags = emptySet(),
|
||||
author = null,
|
||||
description = jo.getString("description"),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import org.jsoup.nodes.Element
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaParser
|
||||
import org.koitharu.kotatsu.parsers.MangaParserAuthProvider
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.exception.AuthRequiredException
|
||||
import org.koitharu.kotatsu.parsers.exception.ParseException
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
@@ -14,16 +15,16 @@ import kotlin.math.pow
|
||||
private const val DOMAIN_UNAUTHORIZED = "e-hentai.org"
|
||||
private const val DOMAIN_AUTHORIZED = "exhentai.org"
|
||||
|
||||
internal class ExHentaiParser(override val context: MangaLoaderContext) : MangaParser(), MangaParserAuthProvider {
|
||||
|
||||
override val source = MangaSource.EXHENTAI
|
||||
internal class ExHentaiParser(
|
||||
override val context: MangaLoaderContext,
|
||||
) : MangaParser(MangaSource.EXHENTAI), MangaParserAuthProvider {
|
||||
|
||||
override val sortOrders: Set<SortOrder> = Collections.singleton(
|
||||
SortOrder.NEWEST,
|
||||
)
|
||||
|
||||
override val defaultDomain: String
|
||||
get() = if (isAuthorized) DOMAIN_AUTHORIZED else DOMAIN_UNAUTHORIZED
|
||||
override val configKeyDomain: ConfigKey.Domain
|
||||
get() = ConfigKey.Domain(if (isAuthorized) DOMAIN_AUTHORIZED else DOMAIN_UNAUTHORIZED, null)
|
||||
|
||||
override val authUrl: String
|
||||
get() = "https://${getDomain()}/bounce_login.php"
|
||||
@@ -118,7 +119,7 @@ internal class ExHentaiParser(override val context: MangaLoaderContext) : MangaP
|
||||
altTitle = null,
|
||||
url = href,
|
||||
publicUrl = a.absUrl("href"),
|
||||
rating = td2.selectFirst("div.ir")?.parseRating() ?: Manga.NO_RATING,
|
||||
rating = td2.selectFirst("div.ir")?.parseRating() ?: RATING_UNKNOWN,
|
||||
isNsfw = true,
|
||||
coverUrl = td1.selectFirst("img")?.absUrl("src").orEmpty(),
|
||||
tags = setOfNotNull(mainTag),
|
||||
@@ -239,7 +240,7 @@ internal class ExHentaiParser(override val context: MangaLoaderContext) : MangaP
|
||||
p1 += 8
|
||||
}
|
||||
(80 - p1) / 80f
|
||||
}.getOrDefault(Manga.NO_RATING)
|
||||
}.getOrDefault(RATING_UNKNOWN)
|
||||
}
|
||||
|
||||
private fun String.cleanupTitle(): String {
|
||||
|
||||
@@ -14,7 +14,7 @@ private const val PAGE_SIZE = 70
|
||||
private const val PAGE_SIZE_SEARCH = 50
|
||||
private const val NSFW_ALERT = "сексуальные сцены"
|
||||
|
||||
internal abstract class GroupleParser : MangaParser() {
|
||||
internal abstract class GroupleParser(source: MangaSource) : MangaParser(source) {
|
||||
|
||||
private val headers = Headers.Builder()
|
||||
.add("User-Agent", "readmangafun")
|
||||
@@ -91,8 +91,9 @@ internal abstract class GroupleParser : MangaParser() {
|
||||
?.substringBefore(' ')
|
||||
?.toFloatOrNull()
|
||||
?.div(10f)
|
||||
}.getOrNull() ?: Manga.NO_RATING,
|
||||
}.getOrNull() ?: RATING_UNKNOWN,
|
||||
author = tileInfo?.selectFirst("a.person-link")?.text(),
|
||||
isNsfw = false,
|
||||
tags = runCatching {
|
||||
tileInfo?.select("a.element-link")
|
||||
?.mapToSet {
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
package org.koitharu.kotatsu.parsers.site
|
||||
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.exception.ParseException
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.util.mapToSet
|
||||
import org.koitharu.kotatsu.parsers.util.parseHtml
|
||||
import org.koitharu.kotatsu.parsers.util.toTitleCase
|
||||
|
||||
internal class HenChanParser(override val context: MangaLoaderContext) : ChanParser() {
|
||||
internal class HenChanParser(override val context: MangaLoaderContext) : ChanParser(MangaSource.HENCHAN) {
|
||||
|
||||
override val defaultDomain = "hentaichan.live"
|
||||
override val source = MangaSource.HENCHAN
|
||||
override val configKeyDomain = ConfigKey.Domain("hentaichan.live", null)
|
||||
|
||||
override suspend fun getList(
|
||||
offset: Int,
|
||||
|
||||
@@ -2,13 +2,11 @@ package org.koitharu.kotatsu.parsers.site
|
||||
|
||||
import org.jsoup.nodes.Document
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
|
||||
internal class HentaiLibParser(context: MangaLoaderContext) : MangaLibParser(context) {
|
||||
|
||||
override val defaultDomain = "hentailib.me"
|
||||
|
||||
override val source = MangaSource.HENTAILIB
|
||||
internal class HentaiLibParser(context: MangaLoaderContext) : MangaLibParser(context, MangaSource.HENTAILIB) {
|
||||
|
||||
override val configKeyDomain = ConfigKey.Domain("hentailib.me", null)
|
||||
override fun isNsfw(doc: Document) = true
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
package org.koitharu.kotatsu.parsers.site
|
||||
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
|
||||
internal class MangaChanParser(override val context: MangaLoaderContext) : ChanParser() {
|
||||
internal class MangaChanParser(override val context: MangaLoaderContext) : ChanParser(MangaSource.MANGACHAN) {
|
||||
|
||||
override val defaultDomain = "manga-chan.me"
|
||||
override val source = MangaSource.MANGACHAN
|
||||
override val configKeyDomain = ConfigKey.Domain("manga-chan.me", null)
|
||||
}
|
||||
@@ -5,6 +5,7 @@ import kotlinx.coroutines.coroutineScope
|
||||
import org.json.JSONObject
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaParser
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
import org.koitharu.kotatsu.parsers.util.json.*
|
||||
@@ -16,10 +17,9 @@ private const val CONTENT_RATING =
|
||||
"contentRating[]=safe&contentRating[]=suggestive&contentRating[]=erotica&contentRating[]=pornographic"
|
||||
private const val LOCALE_FALLBACK = "en"
|
||||
|
||||
internal class MangaDexParser(override val context: MangaLoaderContext) : MangaParser() {
|
||||
internal class MangaDexParser(override val context: MangaLoaderContext) : MangaParser(MangaSource.MANGADEX) {
|
||||
|
||||
override val source = MangaSource.MANGADEX
|
||||
override val defaultDomain = "mangadex.org"
|
||||
override val configKeyDomain = ConfigKey.Domain("mangadex.org", null)
|
||||
|
||||
override val sortOrders: EnumSet<SortOrder> = EnumSet.of(
|
||||
SortOrder.UPDATED,
|
||||
@@ -86,7 +86,7 @@ internal class MangaDexParser(override val context: MangaLoaderContext) : MangaP
|
||||
altTitle = attrs.optJSONObject("altTitles")?.selectByLocale(),
|
||||
url = id,
|
||||
publicUrl = "https://$domain/title/$id",
|
||||
rating = Manga.NO_RATING,
|
||||
rating = RATING_UNKNOWN,
|
||||
isNsfw = attrs.getStringOrNull("contentRating") == "erotica",
|
||||
coverUrl = cover?.plus(".256.jpg").orEmpty(),
|
||||
largeCoverUrl = cover,
|
||||
@@ -114,7 +114,7 @@ internal class MangaDexParser(override val context: MangaLoaderContext) : MangaP
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getDetails(manga: Manga): Manga = coroutineScope<Manga> {
|
||||
override suspend fun getDetails(manga: Manga): Manga = coroutineScope {
|
||||
val domain = getDomain()
|
||||
val attrsDeferred = async {
|
||||
context.httpGet(
|
||||
@@ -169,11 +169,11 @@ internal class MangaDexParser(override val context: MangaLoaderContext) : MangaP
|
||||
|
||||
override suspend fun getPages(chapter: MangaChapter): List<MangaPage> {
|
||||
val domain = getDomain()
|
||||
val chapter = context.httpGet("https://api.$domain/at-home/server/${chapter.url}?forcePort443=false")
|
||||
val chapterJson = context.httpGet("https://api.$domain/at-home/server/${chapter.url}?forcePort443=false")
|
||||
.parseJson()
|
||||
.getJSONObject("chapter")
|
||||
val pages = chapter.getJSONArray("data")
|
||||
val prefix = "https://uploads.$domain/data/${chapter.getString("hash")}/"
|
||||
val pages = chapterJson.getJSONArray("data")
|
||||
val prefix = "https://uploads.$domain/data/${chapterJson.getString("hash")}/"
|
||||
val referer = "https://$domain/"
|
||||
return List(pages.length()) { i ->
|
||||
val url = prefix + pages.getString(i)
|
||||
|
||||
@@ -7,6 +7,7 @@ import org.jsoup.nodes.Document
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaParser
|
||||
import org.koitharu.kotatsu.parsers.MangaParserAuthProvider
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.exception.AuthRequiredException
|
||||
import org.koitharu.kotatsu.parsers.exception.ParseException
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
@@ -17,11 +18,12 @@ import org.koitharu.kotatsu.parsers.util.json.mapJSON
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
internal open class MangaLibParser(override val context: MangaLoaderContext) : MangaParser(), MangaParserAuthProvider {
|
||||
internal open class MangaLibParser(
|
||||
override val context: MangaLoaderContext,
|
||||
source: MangaSource = MangaSource.MANGALIB,
|
||||
) : MangaParser(source), MangaParserAuthProvider {
|
||||
|
||||
override val defaultDomain = "mangalib.me"
|
||||
|
||||
override val source = MangaSource.MANGALIB
|
||||
override val configKeyDomain = ConfigKey.Domain("mangalib.me", null)
|
||||
|
||||
override val authUrl: String
|
||||
get() = "https://${getDomain()}/login"
|
||||
@@ -69,11 +71,12 @@ internal open class MangaLibParser(override val context: MangaLoaderContext) : M
|
||||
coverUrl = a.absUrl("data-src"),
|
||||
altTitle = null,
|
||||
author = null,
|
||||
rating = Manga.NO_RATING,
|
||||
rating = RATING_UNKNOWN,
|
||||
url = href,
|
||||
publicUrl = href.inContextOf(a),
|
||||
tags = emptySet(),
|
||||
state = null,
|
||||
isNsfw = false,
|
||||
source = source,
|
||||
)
|
||||
}
|
||||
@@ -269,8 +272,9 @@ internal open class MangaLibParser(override val context: MangaLoaderContext) : M
|
||||
author = null,
|
||||
tags = emptySet(),
|
||||
rating = jo.getString("rate_avg")
|
||||
.toFloatOrNull()?.div(5f) ?: Manga.NO_RATING,
|
||||
.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN,
|
||||
state = null,
|
||||
isNsfw = false,
|
||||
source = source,
|
||||
coverUrl = covers.getString("thumbnail"),
|
||||
largeCoverUrl = covers.getString("default"),
|
||||
|
||||
@@ -2,17 +2,16 @@ package org.koitharu.kotatsu.parsers.site
|
||||
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaParser
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.exception.ParseException
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
internal class MangaOwlParser(override val context: MangaLoaderContext) : MangaParser() {
|
||||
internal class MangaOwlParser(override val context: MangaLoaderContext) : MangaParser(MangaSource.MANGAOWL) {
|
||||
|
||||
override val source = MangaSource.MANGAOWL
|
||||
|
||||
override val defaultDomain = "mangaowls.com"
|
||||
override val configKeyDomain = ConfigKey.Domain("mangaowls.com", null)
|
||||
|
||||
override val sortOrders: Set<SortOrder> = EnumSet.of(
|
||||
SortOrder.POPULARITY,
|
||||
@@ -62,8 +61,11 @@ internal class MangaOwlParser(override val context: MangaLoaderContext) : MangaP
|
||||
?.text()
|
||||
?.toFloatOrNull()
|
||||
?.div(10f)
|
||||
}.getOrNull() ?: Manga.NO_RATING,
|
||||
}.getOrNull() ?: RATING_UNKNOWN,
|
||||
url = href,
|
||||
isNsfw = false,
|
||||
tags = emptySet(),
|
||||
state = null,
|
||||
publicUrl = href.withDomain(),
|
||||
source = source,
|
||||
)
|
||||
@@ -79,7 +81,7 @@ internal class MangaOwlParser(override val context: MangaLoaderContext) : MangaP
|
||||
val trElement =
|
||||
doc.getElementsByTag("script").find { trRegex.find(it.data()) != null } ?: parseFailed("Oops, tr not found")
|
||||
val tr = trRegex.find(trElement.data())!!.groups[1]!!.value
|
||||
val s = context.encodeBase64(defaultDomain.toByteArray())
|
||||
val s = context.encodeBase64(getDomain().toByteArray())
|
||||
return manga.copy(
|
||||
description = info.selectFirst(".description")?.html(),
|
||||
largeCoverUrl = info.select("img").first()?.let { img ->
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.parsers.site
|
||||
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaParser
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.exception.ParseException
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
@@ -9,11 +10,9 @@ import java.text.DateFormat
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
|
||||
internal class MangaTownParser(override val context: MangaLoaderContext) : MangaParser() {
|
||||
internal class MangaTownParser(override val context: MangaLoaderContext) : MangaParser(MangaSource.MANGATOWN) {
|
||||
|
||||
override val source = MangaSource.MANGATOWN
|
||||
|
||||
override val defaultDomain = "www.mangatown.com"
|
||||
override val configKeyDomain = ConfigKey.Domain("www.mangatown.com", null)
|
||||
|
||||
override val sortOrders: Set<SortOrder> = EnumSet.of(
|
||||
SortOrder.ALPHABETICAL,
|
||||
@@ -69,7 +68,7 @@ internal class MangaTownParser(override val context: MangaLoaderContext) : Manga
|
||||
source = MangaSource.MANGATOWN,
|
||||
altTitle = null,
|
||||
rating = li.selectFirst("p.score")?.selectFirst("b")
|
||||
?.ownText()?.toFloatOrNull()?.div(5f) ?: Manga.NO_RATING,
|
||||
?.ownText()?.toFloatOrNull()?.div(5f) ?: RATING_UNKNOWN,
|
||||
author = views.findText { x -> x.startsWith("Author:") }?.substringAfter(':')
|
||||
?.trim(),
|
||||
state = when (status) {
|
||||
@@ -85,6 +84,7 @@ internal class MangaTownParser(override val context: MangaLoaderContext) : Manga
|
||||
)
|
||||
}.orEmpty(),
|
||||
url = href,
|
||||
isNsfw = false,
|
||||
publicUrl = href.inContextOf(a),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package org.koitharu.kotatsu.parsers.site
|
||||
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaParser
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.exception.ParseException
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
@@ -11,11 +12,9 @@ import java.util.*
|
||||
|
||||
private const val PAGE_SIZE = 12
|
||||
|
||||
internal class MangareadParser(override val context: MangaLoaderContext) : MangaParser() {
|
||||
internal class MangareadParser(override val context: MangaLoaderContext) : MangaParser(MangaSource.MANGAREAD) {
|
||||
|
||||
override val source = MangaSource.MANGAREAD
|
||||
|
||||
override val defaultDomain = "www.mangaread.org"
|
||||
override val configKeyDomain = ConfigKey.Domain("www.mangaread.org", null)
|
||||
|
||||
override val sortOrders: Set<SortOrder> = EnumSet.of(
|
||||
SortOrder.UPDATED,
|
||||
@@ -56,6 +55,7 @@ internal class MangareadParser(override val context: MangaLoaderContext) : Manga
|
||||
publicUrl = href.inContextOf(div),
|
||||
coverUrl = div.selectFirst("img")?.absUrl("data-src").orEmpty(),
|
||||
title = summary?.selectFirst("h3")?.text().orEmpty(),
|
||||
altTitle = null,
|
||||
rating = div.selectFirst("span.total_votes")?.ownText()
|
||||
?.toFloatOrNull()?.div(5f) ?: -1f,
|
||||
tags = summary?.selectFirst(".mg_genres")?.select("a")?.mapToSet { a ->
|
||||
@@ -75,6 +75,7 @@ internal class MangareadParser(override val context: MangaLoaderContext) : Manga
|
||||
else -> null
|
||||
},
|
||||
source = MangaSource.MANGAREAD,
|
||||
isNsfw = false,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package org.koitharu.kotatsu.parsers.site
|
||||
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
|
||||
internal class MintMangaParser(override val context: MangaLoaderContext) : GroupleParser() {
|
||||
internal class MintMangaParser(override val context: MangaLoaderContext) : GroupleParser(MangaSource.MINTMANGA) {
|
||||
|
||||
override val source = MangaSource.MINTMANGA
|
||||
override val defaultDomain: String = "mintmanga.live"
|
||||
override val configKeyDomain = ConfigKey.Domain("mintmanga.live", null)
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import okhttp3.Headers
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaParser
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.exception.ParseException
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
@@ -14,9 +15,11 @@ private const val PAGE_SIZE = 26
|
||||
|
||||
internal abstract class NineMangaParser(
|
||||
final override val context: MangaLoaderContext,
|
||||
final override val source: MangaSource,
|
||||
final override val defaultDomain: String,
|
||||
) : MangaParser() {
|
||||
source: MangaSource,
|
||||
defaultDomain: String,
|
||||
) : MangaParser(source) {
|
||||
|
||||
override val configKeyDomain = ConfigKey.Domain(defaultDomain, null)
|
||||
|
||||
init {
|
||||
context.cookieJar.insertCookies(getDomain(), "ninemanga_template_desk=yes")
|
||||
@@ -77,8 +80,9 @@ internal abstract class NineMangaParser(
|
||||
title = dd?.selectFirst("a.bookname")?.text()?.toCamelCase().orEmpty(),
|
||||
altTitle = null,
|
||||
coverUrl = node.selectFirst("img")?.absUrl("src").orEmpty(),
|
||||
rating = Manga.NO_RATING,
|
||||
rating = RATING_UNKNOWN,
|
||||
author = null,
|
||||
isNsfw = false,
|
||||
tags = emptySet(),
|
||||
state = null,
|
||||
source = source,
|
||||
|
||||
@@ -4,6 +4,7 @@ import androidx.collection.SparseArrayCompat
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaParser
|
||||
import org.koitharu.kotatsu.parsers.MangaParserAuthProvider
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.exception.AuthRequiredException
|
||||
import org.koitharu.kotatsu.parsers.exception.ParseException
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
@@ -12,10 +13,11 @@ import java.text.SimpleDateFormat
|
||||
import java.util.*
|
||||
import java.util.regex.Pattern
|
||||
|
||||
internal class NudeMoonParser(override val context: MangaLoaderContext) : MangaParser(), MangaParserAuthProvider {
|
||||
internal class NudeMoonParser(
|
||||
override val context: MangaLoaderContext,
|
||||
) : MangaParser(MangaSource.NUDEMOON), MangaParserAuthProvider {
|
||||
|
||||
override val source = MangaSource.NUDEMOON
|
||||
override val defaultDomain = "nude-moon.net"
|
||||
override val configKeyDomain = ConfigKey.Domain("nude-moon.net", null)
|
||||
override val authUrl: String
|
||||
get() = "https://${getDomain()}/index.php"
|
||||
|
||||
@@ -89,7 +91,7 @@ internal class NudeMoonParser(override val context: MangaLoaderContext) : MangaP
|
||||
}.orEmpty(),
|
||||
source = source,
|
||||
publicUrl = a.absUrl("href"),
|
||||
rating = Manga.NO_RATING,
|
||||
rating = RATING_UNKNOWN,
|
||||
isNsfw = true,
|
||||
description = row.selectFirst("div.description")?.html(),
|
||||
state = null,
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package org.koitharu.kotatsu.parsers.site
|
||||
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
|
||||
internal class ReadmangaParser(override val context: MangaLoaderContext) : GroupleParser() {
|
||||
internal class ReadmangaParser(override val context: MangaLoaderContext) : GroupleParser(MangaSource.READMANGA_RU) {
|
||||
|
||||
override val defaultDomain = "readmanga.io"
|
||||
override val source = MangaSource.READMANGA_RU
|
||||
override val configKeyDomain = ConfigKey.Domain("readmanga.io", null)
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import org.json.JSONObject
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.MangaParser
|
||||
import org.koitharu.kotatsu.parsers.MangaParserAuthProvider
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.exception.ParseException
|
||||
import org.koitharu.kotatsu.parsers.model.*
|
||||
import org.koitharu.kotatsu.parsers.util.*
|
||||
@@ -23,11 +24,11 @@ private const val PAGE_SIZE = 30
|
||||
private const val STATUS_ONGOING = 1
|
||||
private const val STATUS_FINISHED = 0
|
||||
|
||||
internal class RemangaParser(override val context: MangaLoaderContext) : MangaParser(), MangaParserAuthProvider {
|
||||
internal class RemangaParser(
|
||||
override val context: MangaLoaderContext,
|
||||
) : MangaParser(MangaSource.REMANGA), MangaParserAuthProvider {
|
||||
|
||||
override val source = MangaSource.REMANGA
|
||||
|
||||
override val defaultDomain = "remanga.org"
|
||||
override val configKeyDomain = ConfigKey.Domain("remanga.org", null)
|
||||
override val authUrl: String
|
||||
get() = "https://${getDomain()}/user/login"
|
||||
|
||||
@@ -85,10 +86,12 @@ internal class RemangaParser(override val context: MangaLoaderContext) : MangaPa
|
||||
publicUrl = "https://$domain$url",
|
||||
title = jo.getString("rus_name"),
|
||||
altTitle = jo.getString("en_name"),
|
||||
rating = jo.getString("avg_rating").toFloatOrNull()?.div(10f) ?: Manga.NO_RATING,
|
||||
rating = jo.getString("avg_rating").toFloatOrNull()?.div(10f) ?: RATING_UNKNOWN,
|
||||
coverUrl = "https://api.$domain${img.getString("mid")}",
|
||||
largeCoverUrl = "https://api.$domain${img.getString("high")}",
|
||||
author = null,
|
||||
isNsfw = false,
|
||||
state = null,
|
||||
tags = jo.optJSONArray("genres")?.mapJSONToSet { g ->
|
||||
MangaTag(
|
||||
title = g.getString("name").toTitleCase(),
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
package org.koitharu.kotatsu.parsers.site
|
||||
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
|
||||
internal class SelfMangaParser(override val context: MangaLoaderContext) : GroupleParser() {
|
||||
internal class SelfMangaParser(override val context: MangaLoaderContext) : GroupleParser(MangaSource.SELFMANGA) {
|
||||
|
||||
override val defaultDomain = "selfmanga.live"
|
||||
override val source = MangaSource.SELFMANGA
|
||||
override val configKeyDomain = ConfigKey.Domain("selfmanga.live", null)
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package org.koitharu.kotatsu.parsers.site
|
||||
|
||||
import org.koitharu.kotatsu.parsers.MangaLoaderContext
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.exception.ParseException
|
||||
import org.koitharu.kotatsu.parsers.model.Manga
|
||||
import org.koitharu.kotatsu.parsers.model.MangaChapter
|
||||
@@ -8,10 +9,9 @@ import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.util.parseHtml
|
||||
import org.koitharu.kotatsu.parsers.util.relUrl
|
||||
|
||||
internal class YaoiChanParser(override val context: MangaLoaderContext) : ChanParser() {
|
||||
internal class YaoiChanParser(override val context: MangaLoaderContext) : ChanParser(MangaSource.YAOICHAN) {
|
||||
|
||||
override val source = MangaSource.YAOICHAN
|
||||
override val defaultDomain = "yaoi-chan.me"
|
||||
override val configKeyDomain = ConfigKey.Domain("yaoi-chan.me", null)
|
||||
|
||||
override suspend fun getDetails(manga: Manga): Manga {
|
||||
val doc = context.httpGet(manga.url.withDomain()).parseHtml()
|
||||
|
||||
@@ -32,7 +32,7 @@ class InMemoryCookieJar : CookieJar {
|
||||
if (line.isBlank() || line.startsWith("# ")) {
|
||||
continue
|
||||
}
|
||||
val (host, includeSubdomains, path, secure, expire, name, value) = line.split(Regex("\\s+"))
|
||||
val (host, _, path, secure, expire, name, value) = line.split(Regex("\\s+"))
|
||||
val domain = host.removePrefix("#HttpOnly_").trimStart('.')
|
||||
val httpOnly = host.startsWith("#HttpOnly_")
|
||||
val cookie = Cookie.Builder()
|
||||
|
||||
@@ -4,6 +4,7 @@ import com.koushikdutta.quack.QuackContext
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.koitharu.kotatsu.parsers.config.MangaSourceConfig
|
||||
import org.koitharu.kotatsu.parsers.model.MangaSource
|
||||
import org.koitharu.kotatsu.parsers.util.await
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
package org.koitharu.kotatsu.parsers
|
||||
|
||||
import org.koitharu.kotatsu.parsers.config.ConfigKey
|
||||
import org.koitharu.kotatsu.parsers.config.MangaSourceConfig
|
||||
|
||||
internal class SourceConfigMock : MangaSourceConfig {
|
||||
|
||||
override fun getDomain(defaultValue: String): String = defaultValue
|
||||
|
||||
override fun isSslEnabled(defaultValue: Boolean): Boolean = defaultValue
|
||||
override fun <T> get(key: ConfigKey<T>): T = key.defaultValue
|
||||
}
|
||||
Reference in New Issue
Block a user