fix(nhentaicom): fix image and language loading errors. (#10412)
* fix(nhentaicom): lang code error * fix(nhentaicom): token parse error * chore(nhentaicom): update version code * fix(nhentaicom): fix 403 error * fix(nhentaicom): Fix HentaiHand image loading when logged in The token interceptor was incorrectly trying to add a token to image requests, which are not on the source's domain, causing image loading to fail when logged in. * fix(nhentai): fix null description * wip: restore code from the crashed rog laptop. * refactor: use @Serializable * fix: parse error * wip: use keiyoushi.utils.parseAs
This commit is contained in:
parent
d4d2785853
commit
6a29aa1afd
@ -2,4 +2,4 @@ plugins {
|
|||||||
id("lib-multisrc")
|
id("lib-multisrc")
|
||||||
}
|
}
|
||||||
|
|
||||||
baseVersionCode = 3
|
baseVersionCode = 4
|
||||||
|
|||||||
@ -0,0 +1,135 @@
|
|||||||
|
@file:Suppress("PrivatePropertyName", "PropertyName")
|
||||||
|
|
||||||
|
package eu.kanade.tachiyomi.multisrc.hentaihand
|
||||||
|
|
||||||
|
import eu.kanade.tachiyomi.source.model.Page
|
||||||
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
|
import kotlinx.serialization.Serializable
|
||||||
|
import java.text.SimpleDateFormat
|
||||||
|
import java.util.Calendar
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Created by ipcjs on 2025/9/23.
|
||||||
|
*/
|
||||||
|
@Serializable
|
||||||
|
class ResponseDto<T>(
|
||||||
|
val data: T,
|
||||||
|
val next_page_url: String?,
|
||||||
|
)
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class LoginResponseDto(val auth: AuthDto) {
|
||||||
|
@Serializable
|
||||||
|
class AuthDto(val access_token: String)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class PageListResponseDto(val images: List<PageDto>) {
|
||||||
|
fun toPageList() = images.map { Page(it.page, "", it.source_url) }
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class PageDto(
|
||||||
|
val page: Int,
|
||||||
|
val source_url: String,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
typealias ChapterListResponseDto = List<ChapterDto>
|
||||||
|
typealias ChapterResponseDto = ChapterDto
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class ChapterDto(
|
||||||
|
private val slug: String,
|
||||||
|
private val name: String?,
|
||||||
|
private val added_at: String?,
|
||||||
|
private val updated_at: String?,
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
private val DATE_FORMAT = SimpleDateFormat("yyyy-MM-dd", Locale.US)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseDate(date: String?): Long =
|
||||||
|
if (date == null) {
|
||||||
|
0
|
||||||
|
} else if (date.contains("day")) {
|
||||||
|
Calendar.getInstance().apply {
|
||||||
|
add(Calendar.DATE, -date.filter { it.isDigit() }.toInt())
|
||||||
|
}.timeInMillis
|
||||||
|
} else {
|
||||||
|
DATE_FORMAT.parse(date)?.time ?: 0
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toSChapter(slug: String) = SChapter.create().also { chapter ->
|
||||||
|
chapter.url = "$slug/${this.slug}"
|
||||||
|
chapter.name = name ?: "Chapter"
|
||||||
|
chapter.date_upload = parseDate(added_at)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toSChapter() = SChapter.create().also { chapter ->
|
||||||
|
chapter.url = slug
|
||||||
|
chapter.name = "Chapter"
|
||||||
|
chapter.date_upload = parseDate(updated_at)
|
||||||
|
chapter.chapter_number = 1f
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
typealias MangaDetailsResponseDto = MangaDto
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class MangaDto(
|
||||||
|
private val slug: String,
|
||||||
|
private val title: String,
|
||||||
|
private val image_url: String?,
|
||||||
|
private val artists: List<NameDto>?,
|
||||||
|
private val authors: List<NameDto>?,
|
||||||
|
private val tags: List<NameDto>?,
|
||||||
|
private val relationships: List<NameDto>?,
|
||||||
|
private val status: String?,
|
||||||
|
private val alternative_title: String?,
|
||||||
|
private val groups: List<NameDto>?,
|
||||||
|
private val description: String?,
|
||||||
|
private val pages: Int?,
|
||||||
|
private val category: NameDto?,
|
||||||
|
private val language: NameDto?,
|
||||||
|
private val parodies: List<NameDto>?,
|
||||||
|
private val characters: List<NameDto>?,
|
||||||
|
) {
|
||||||
|
fun toSManga() = SManga.create().also { manga ->
|
||||||
|
manga.url = slug.prependIndent("/en/comic/")
|
||||||
|
manga.title = title
|
||||||
|
manga.thumbnail_url = image_url
|
||||||
|
}
|
||||||
|
|
||||||
|
fun toSMangaDetails() = toSManga().also { manga ->
|
||||||
|
manga.artist = artists?.toNames()
|
||||||
|
manga.author = authors?.toNames() ?: manga.artist
|
||||||
|
manga.genre = listOfNotNull(tags, relationships).flatten().toNames()
|
||||||
|
manga.status = when (status) {
|
||||||
|
"complete" -> SManga.COMPLETED
|
||||||
|
"ongoing" -> SManga.ONGOING
|
||||||
|
"onhold" -> SManga.ONGOING
|
||||||
|
"canceled" -> SManga.COMPLETED
|
||||||
|
else -> SManga.COMPLETED
|
||||||
|
}
|
||||||
|
manga.description = listOf(
|
||||||
|
Pair("Alternative Title", alternative_title),
|
||||||
|
Pair("Groups", groups?.toNames()),
|
||||||
|
Pair("Description", description),
|
||||||
|
Pair("Pages", pages?.toString()),
|
||||||
|
Pair("Category", category?.name),
|
||||||
|
Pair("Language", language?.name),
|
||||||
|
Pair("Parodies", parodies?.toNames()),
|
||||||
|
Pair("Characters", characters?.toNames()),
|
||||||
|
).filter { !it.second.isNullOrEmpty() }.joinToString("\n\n") { "${it.first}: ${it.second}" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class NameDto(val name: String)
|
||||||
|
|
||||||
|
fun List<NameDto>.toNames() = if (this.isEmpty()) null else this.joinToString { it.name }
|
||||||
|
|
||||||
|
@Serializable
|
||||||
|
class IdDto(val id: String)
|
||||||
@ -16,13 +16,8 @@ import eu.kanade.tachiyomi.source.model.SChapter
|
|||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.source.online.HttpSource
|
import eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import keiyoushi.utils.getPreferencesLazy
|
import keiyoushi.utils.getPreferencesLazy
|
||||||
import kotlinx.serialization.json.Json
|
import keiyoushi.utils.parseAs
|
||||||
import kotlinx.serialization.json.JsonObject
|
|
||||||
import kotlinx.serialization.json.buildJsonObject
|
import kotlinx.serialization.json.buildJsonObject
|
||||||
import kotlinx.serialization.json.int
|
|
||||||
import kotlinx.serialization.json.jsonArray
|
|
||||||
import kotlinx.serialization.json.jsonObject
|
|
||||||
import kotlinx.serialization.json.jsonPrimitive
|
|
||||||
import kotlinx.serialization.json.put
|
import kotlinx.serialization.json.put
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
import okhttp3.Interceptor
|
import okhttp3.Interceptor
|
||||||
@ -32,10 +27,8 @@ import okhttp3.RequestBody.Companion.toRequestBody
|
|||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import rx.schedulers.Schedulers
|
import rx.schedulers.Schedulers
|
||||||
import uy.kohesive.injekt.injectLazy
|
|
||||||
import java.io.IOException
|
import java.io.IOException
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Calendar
|
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
abstract class HentaiHand(
|
abstract class HentaiHand(
|
||||||
@ -48,32 +41,15 @@ abstract class HentaiHand(
|
|||||||
|
|
||||||
override val supportsLatest = true
|
override val supportsLatest = true
|
||||||
|
|
||||||
private val json: Json by injectLazy()
|
override fun headersBuilder() = super.headersBuilder()
|
||||||
|
.add("Referer", "$baseUrl/")
|
||||||
private fun slugToUrl(json: JsonObject) = json["slug"]!!.jsonPrimitive.content.prependIndent("/en/comic/")
|
|
||||||
|
|
||||||
private fun jsonArrayToString(arrayKey: String, obj: JsonObject): String? {
|
|
||||||
val array = obj[arrayKey]!!.jsonArray
|
|
||||||
if (array.isEmpty()) return null
|
|
||||||
return array.joinToString(", ") {
|
|
||||||
it.jsonObject["name"]!!.jsonPrimitive.content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Popular
|
// Popular
|
||||||
|
|
||||||
override fun popularMangaParse(response: Response): MangasPage {
|
override fun popularMangaParse(response: Response): MangasPage {
|
||||||
val jsonResponse = json.parseToJsonElement(response.body.string())
|
val resp = response.parseAs<ResponseDto<List<MangaDto>>>()
|
||||||
val mangaList = jsonResponse.jsonObject["data"]!!.jsonArray.map {
|
val hasNextPage = !resp.next_page_url.isNullOrEmpty()
|
||||||
val obj = it.jsonObject
|
return MangasPage(resp.data.map { it.toSManga() }, hasNextPage)
|
||||||
SManga.create().apply {
|
|
||||||
url = slugToUrl(obj)
|
|
||||||
title = obj["title"]!!.jsonPrimitive.content
|
|
||||||
thumbnail_url = obj["image_url"]!!.jsonPrimitive.content
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val hasNextPage = jsonResponse.jsonObject["next_page_url"]!!.jsonPrimitive.content.isNotEmpty()
|
|
||||||
return MangasPage(mangaList, hasNextPage)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun popularMangaRequest(page: Int): Request {
|
override fun popularMangaRequest(page: Int): Request {
|
||||||
@ -116,9 +92,7 @@ abstract class HentaiHand(
|
|||||||
.subscribeOn(Schedulers.io())
|
.subscribeOn(Schedulers.io())
|
||||||
.map { response ->
|
.map { response ->
|
||||||
// Returns the first matched id, or null if there are no results
|
// Returns the first matched id, or null if there are no results
|
||||||
val idList = json.parseToJsonElement(response.body.string()).jsonObject["data"]!!.jsonArray.map {
|
val idList = response.parseAs<ResponseDto<List<IdDto>>>().data.map { it.id }
|
||||||
it.jsonObject["id"]!!.jsonPrimitive.content
|
|
||||||
}
|
|
||||||
if (idList.isEmpty()) {
|
if (idList.isEmpty()) {
|
||||||
return@map null
|
return@map null
|
||||||
} else {
|
} else {
|
||||||
@ -177,33 +151,7 @@ abstract class HentaiHand(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun mangaDetailsParse(response: Response): SManga {
|
override fun mangaDetailsParse(response: Response): SManga {
|
||||||
val obj = json.parseToJsonElement(response.body.string()).jsonObject
|
return response.parseAs<MangaDetailsResponseDto>().toSMangaDetails()
|
||||||
return SManga.create().apply {
|
|
||||||
url = slugToUrl(obj)
|
|
||||||
title = obj["title"]!!.jsonPrimitive.content
|
|
||||||
thumbnail_url = obj["image_url"]!!.jsonPrimitive.content
|
|
||||||
artist = jsonArrayToString("artists", obj)
|
|
||||||
author = jsonArrayToString("authors", obj) ?: artist
|
|
||||||
genre = listOfNotNull(jsonArrayToString("tags", obj), jsonArrayToString("relationships", obj)).joinToString(", ")
|
|
||||||
status = when (obj["status"]!!.jsonPrimitive.content) {
|
|
||||||
"complete" -> SManga.COMPLETED
|
|
||||||
"ongoing" -> SManga.ONGOING
|
|
||||||
"onhold" -> SManga.ONGOING
|
|
||||||
"canceled" -> SManga.COMPLETED
|
|
||||||
else -> SManga.COMPLETED
|
|
||||||
}
|
|
||||||
|
|
||||||
description = listOf(
|
|
||||||
Pair("Alternative Title", obj["alternative_title"]!!.jsonPrimitive.content),
|
|
||||||
Pair("Groups", jsonArrayToString("groups", obj)),
|
|
||||||
Pair("Description", obj["description"]!!.jsonPrimitive.content),
|
|
||||||
Pair("Pages", obj["pages"]!!.jsonPrimitive.content),
|
|
||||||
Pair("Category", try { obj["category"]!!.jsonObject["name"]!!.jsonPrimitive.content } catch (_: Exception) { null }),
|
|
||||||
Pair("Language", try { obj["language"]!!.jsonObject["name"]!!.jsonPrimitive.content } catch (_: Exception) { null }),
|
|
||||||
Pair("Parodies", jsonArrayToString("parodies", obj)),
|
|
||||||
Pair("Characters", jsonArrayToString("characters", obj)),
|
|
||||||
).filter { !it.second.isNullOrEmpty() }.joinToString("\n\n") { "${it.first}: ${it.second}" }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chapters
|
// Chapters
|
||||||
@ -220,40 +168,13 @@ abstract class HentaiHand(
|
|||||||
override fun chapterListRequest(manga: SManga): Request = chapterListApiRequest(manga)
|
override fun chapterListRequest(manga: SManga): Request = chapterListApiRequest(manga)
|
||||||
|
|
||||||
override fun chapterListParse(response: Response): List<SChapter> {
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
val slug = response.request.url.toString().substringAfter("/api/comics/").removeSuffix("/chapters")
|
return if (this.chapters) {
|
||||||
return if (chapters) {
|
val slug = response.request.url.toString()
|
||||||
val array = json.parseToJsonElement(response.body.string()).jsonArray
|
.substringAfter("/api/comics/")
|
||||||
array.map {
|
.removeSuffix("/chapters")
|
||||||
SChapter.create().apply {
|
response.parseAs<ChapterListResponseDto>().map { it.toSChapter(slug) }
|
||||||
url = "$slug/${it.jsonObject["slug"]!!.jsonPrimitive.content}"
|
|
||||||
name = it.jsonObject["name"]!!.jsonPrimitive.content
|
|
||||||
val date = it.jsonObject["added_at"]!!.jsonPrimitive.content
|
|
||||||
date_upload = if (date.contains("day")) {
|
|
||||||
Calendar.getInstance().apply {
|
|
||||||
add(Calendar.DATE, -date.filter { it.isDigit() }.toInt())
|
|
||||||
}.timeInMillis
|
|
||||||
} else {
|
} else {
|
||||||
DATE_FORMAT.parse(it.jsonObject["added_at"]!!.jsonPrimitive.content)?.time ?: 0
|
listOf(response.parseAs<ChapterResponseDto>().toSChapter())
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
val obj = json.parseToJsonElement(response.body.string()).jsonObject
|
|
||||||
listOf(
|
|
||||||
SChapter.create().apply {
|
|
||||||
url = obj["slug"]!!.jsonPrimitive.content
|
|
||||||
name = "Chapter"
|
|
||||||
val date = obj.jsonObject["uploaded_at"]!!.jsonPrimitive.content
|
|
||||||
date_upload = if (date.contains("day")) {
|
|
||||||
Calendar.getInstance().apply {
|
|
||||||
add(Calendar.DATE, -date.filter { it.isDigit() }.toInt())
|
|
||||||
}.timeInMillis
|
|
||||||
} else {
|
|
||||||
DATE_FORMAT.parse(obj.jsonObject["uploaded_at"]!!.jsonPrimitive.content)?.time ?: 0
|
|
||||||
}
|
|
||||||
chapter_number = 1f
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -264,13 +185,7 @@ abstract class HentaiHand(
|
|||||||
return GET("$baseUrl/api/comics/$slug/images")
|
return GET("$baseUrl/api/comics/$slug/images")
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun pageListParse(response: Response): List<Page> =
|
override fun pageListParse(response: Response): List<Page> = response.parseAs<PageListResponseDto>().toPageList()
|
||||||
json.parseToJsonElement(response.body.string()).jsonObject["images"]!!.jsonArray.map {
|
|
||||||
val imgObj = it.jsonObject
|
|
||||||
val index = imgObj["page"]!!.jsonPrimitive.int
|
|
||||||
val imgUrl = imgObj["source_url"]!!.jsonPrimitive.content
|
|
||||||
Page(index, "", imgUrl)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun imageUrlParse(response: Response): String = throw UnsupportedOperationException()
|
override fun imageUrlParse(response: Response): String = throw UnsupportedOperationException()
|
||||||
|
|
||||||
@ -278,7 +193,10 @@ abstract class HentaiHand(
|
|||||||
|
|
||||||
protected fun authIntercept(chain: Interceptor.Chain): Response {
|
protected fun authIntercept(chain: Interceptor.Chain): Response {
|
||||||
val request = chain.request()
|
val request = chain.request()
|
||||||
if (username.isEmpty() or password.isEmpty()) {
|
if (username.isEmpty() or password.isEmpty()
|
||||||
|
// image request doesn't need token
|
||||||
|
or !request.url.toString().startsWith(baseUrl)
|
||||||
|
) {
|
||||||
return chain.proceed(request)
|
return chain.proceed(request)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,7 +222,7 @@ abstract class HentaiHand(
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
// Returns access token as a string, unless unparseable
|
// Returns access token as a string, unless unparseable
|
||||||
return json.parseToJsonElement(response.body.string()).jsonObject["auth"]!!.jsonObject["access-token"]!!.jsonPrimitive.content
|
return response.parseAs<LoginResponseDto>().auth.access_token
|
||||||
} catch (e: IllegalArgumentException) {
|
} catch (e: IllegalArgumentException) {
|
||||||
throw IOException("Cannot parse login response body")
|
throw IOException("Cannot parse login response body")
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,7 +3,7 @@ ext {
|
|||||||
extClass = '.NHentaiComFactory'
|
extClass = '.NHentaiComFactory'
|
||||||
themePkg = 'hentaihand'
|
themePkg = 'hentaihand'
|
||||||
baseUrl = 'https://nhentai.com'
|
baseUrl = 'https://nhentai.com'
|
||||||
overrideVersionCode = 4
|
overrideVersionCode = 5
|
||||||
isNsfw = true
|
isNsfw = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,39 +9,27 @@ class NHentaiComFactory : SourceFactory {
|
|||||||
override fun createSources(): List<Source> = listOf(
|
override fun createSources(): List<Source> = listOf(
|
||||||
// https://nhentai.com/api/languages?per_page=50
|
// https://nhentai.com/api/languages?per_page=50
|
||||||
NHentaiComAll(),
|
NHentaiComAll(),
|
||||||
NHentaiComEn(),
|
|
||||||
NHentaiComZh(),
|
NHentaiComZh(),
|
||||||
|
NHentaiComEn(),
|
||||||
NHentaiComJa(),
|
NHentaiComJa(),
|
||||||
NHentaiComNoText(),
|
NHentaiComNoText(),
|
||||||
NHentaiComEo(),
|
|
||||||
NHentaiComCeb(),
|
|
||||||
NHentaiComCs(),
|
|
||||||
NHentaiComAr(),
|
NHentaiComAr(),
|
||||||
NHentaiComSk(),
|
|
||||||
NHentaiComMn(),
|
|
||||||
NHentaiComUk(),
|
|
||||||
NHentaiComLa(),
|
|
||||||
NHentaiComTl(),
|
|
||||||
NHentaiComEs(),
|
|
||||||
NHentaiComIt(),
|
|
||||||
NHentaiComKo(),
|
|
||||||
NHentaiComTh(),
|
|
||||||
NHentaiComPl(),
|
|
||||||
NHentaiComFr(),
|
|
||||||
NHentaiComPtBr(),
|
|
||||||
NHentaiComDe(),
|
|
||||||
NHentaiComFi(),
|
|
||||||
NHentaiComRu(),
|
|
||||||
NHentaiComHu(),
|
|
||||||
NHentaiComId(),
|
|
||||||
NHentaiComVi(),
|
|
||||||
NHentaiComNl(),
|
|
||||||
NHentaiComTr(),
|
|
||||||
NHentaiComEl(),
|
|
||||||
NHentaiComBg(),
|
|
||||||
NHentaiComSr(),
|
|
||||||
NHentaiComJv(),
|
NHentaiComJv(),
|
||||||
NHentaiComHi(),
|
NHentaiComBg(),
|
||||||
|
NHentaiComCs(),
|
||||||
|
NHentaiComUk(),
|
||||||
|
NHentaiComSk(),
|
||||||
|
NHentaiComEo(),
|
||||||
|
NHentaiComMn(),
|
||||||
|
NHentaiComLa(),
|
||||||
|
NHentaiComCeb(),
|
||||||
|
NHentaiComTl(),
|
||||||
|
NHentaiComFi(),
|
||||||
|
NHentaiComTr(),
|
||||||
|
NHentaiComSr(),
|
||||||
|
NHentaiComEl(),
|
||||||
|
NHentaiComKo(),
|
||||||
|
NHentaiComRo(),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
abstract class NHentaiComCommon(
|
abstract class NHentaiComCommon(
|
||||||
@ -58,42 +46,30 @@ class NHentaiComAll : NHentaiComCommon("all") {
|
|||||||
override val id: Long = 9165839893600661480
|
override val id: Long = 9165839893600661480
|
||||||
}
|
}
|
||||||
|
|
||||||
class NHentaiComJa : NHentaiComCommon("ja", listOf(1, 29))
|
class NHentaiComZh : NHentaiComCommon("zh", listOf(1))
|
||||||
class NHentaiComEn : NHentaiComCommon("en", listOf(2, 27)) {
|
class NHentaiComEn : NHentaiComCommon("en", listOf(2)) {
|
||||||
override val id: Long = 5591830863732393712
|
override val id: Long = 5591830863732393712
|
||||||
}
|
}
|
||||||
class NHentaiComZh : NHentaiComCommon("zh", listOf(3, 50))
|
class NHentaiComJa : NHentaiComCommon("ja", listOf(3))
|
||||||
class NHentaiComBg : NHentaiComCommon("bg", listOf(4))
|
class NHentaiComNoText : NHentaiComCommon("other", listOf(4)) {
|
||||||
class NHentaiComCeb : NHentaiComCommon("ceb", listOf(5, 44))
|
|
||||||
class NHentaiComNoText : NHentaiComCommon("other", listOf(6)) {
|
|
||||||
override val id: Long = 5817327335315373850
|
override val id: Long = 5817327335315373850
|
||||||
}
|
}
|
||||||
class NHentaiComTl : NHentaiComCommon("tl", listOf(7, 55))
|
class NHentaiComAr : NHentaiComCommon("ar", listOf(5))
|
||||||
class NHentaiComAr : NHentaiComCommon("ar", listOf(8, 49))
|
class NHentaiComJv : NHentaiComCommon("jv", listOf(6))
|
||||||
class NHentaiComEl : NHentaiComCommon("el", listOf(9))
|
class NHentaiComBg : NHentaiComCommon("bg", listOf(7))
|
||||||
class NHentaiComSr : NHentaiComCommon("sr", listOf(10))
|
class NHentaiComCs : NHentaiComCommon("cs", listOf(8)) {
|
||||||
class NHentaiComJv : NHentaiComCommon("jv", listOf(11, 51))
|
|
||||||
class NHentaiComUk : NHentaiComCommon("uk", listOf(12, 46))
|
|
||||||
class NHentaiComTr : NHentaiComCommon("tr", listOf(13, 41))
|
|
||||||
class NHentaiComFi : NHentaiComCommon("fi", listOf(14, 54))
|
|
||||||
class NHentaiComLa : NHentaiComCommon("la", listOf(15))
|
|
||||||
class NHentaiComMn : NHentaiComCommon("mn", listOf(16))
|
|
||||||
class NHentaiComEo : NHentaiComCommon("eo", listOf(17, 47))
|
|
||||||
class NHentaiComSk : NHentaiComCommon("sk", listOf(18))
|
|
||||||
class NHentaiComCs : NHentaiComCommon("cs", listOf(19, 52)) {
|
|
||||||
override val id: Long = 1144495813995437124
|
override val id: Long = 1144495813995437124
|
||||||
}
|
}
|
||||||
class NHentaiComKo : NHentaiComCommon("ko", listOf(30, 39))
|
class NHentaiComUk : NHentaiComCommon("uk", listOf(9))
|
||||||
class NHentaiComRu : NHentaiComCommon("ru", listOf(31))
|
class NHentaiComSk : NHentaiComCommon("sk", listOf(10))
|
||||||
class NHentaiComIt : NHentaiComCommon("it", listOf(32))
|
class NHentaiComEo : NHentaiComCommon("eo", listOf(11))
|
||||||
class NHentaiComEs : NHentaiComCommon("es", listOf(33, 37))
|
class NHentaiComMn : NHentaiComCommon("mn", listOf(12))
|
||||||
class NHentaiComPtBr : NHentaiComCommon("pt-BR", listOf(34))
|
class NHentaiComLa : NHentaiComCommon("la", listOf(13))
|
||||||
class NHentaiComTh : NHentaiComCommon("th", listOf(35, 40))
|
class NHentaiComCeb : NHentaiComCommon("ceb", listOf(14))
|
||||||
class NHentaiComFr : NHentaiComCommon("fr", listOf(36))
|
class NHentaiComTl : NHentaiComCommon("tl", listOf(15))
|
||||||
class NHentaiComId : NHentaiComCommon("id", listOf(38))
|
class NHentaiComFi : NHentaiComCommon("fi", listOf(16))
|
||||||
class NHentaiComVi : NHentaiComCommon("vi", listOf(42))
|
class NHentaiComTr : NHentaiComCommon("tr", listOf(17))
|
||||||
class NHentaiComDe : NHentaiComCommon("de", listOf(43))
|
class NHentaiComSr : NHentaiComCommon("sr", listOf(18))
|
||||||
class NHentaiComPl : NHentaiComCommon("pl", listOf(45))
|
class NHentaiComEl : NHentaiComCommon("el", listOf(19))
|
||||||
class NHentaiComHu : NHentaiComCommon("hu", listOf(48))
|
class NHentaiComKo : NHentaiComCommon("ko", listOf(20))
|
||||||
class NHentaiComNl : NHentaiComCommon("nl", listOf(53))
|
class NHentaiComRo : NHentaiComCommon("ro", listOf(21))
|
||||||
class NHentaiComHi : NHentaiComCommon("hi", listOf(56))
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user