nHentai.com switch to kotlinx and add support for multilang (#7990)

* Create NHentaiCom.kt

* Create NHentaiComFactory.kt

* Create NHentaiCom.kt

* Delete NHentaiCom.kt

* Create build.gradle

* Create AndroidManifest.xml

* Added Icons

* Remove Single Lang files

* Added (unoriginal) back to naming

* Changed name back to (unoriginal) ending

* Removed Langues

* Update NHentaiComFactory.kt

* Update NHentaiCom.kt

* change from try to runCatching
This commit is contained in:
Johannes Joens 2021-07-07 21:52:33 +12:00 committed by GitHub
parent 6f00690c8e
commit 03850d43a7
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 105 additions and 60 deletions

View File

@ -3,9 +3,9 @@ apply plugin: 'kotlin-android'
ext {
extName = 'nHentai.com (unoriginal)'
pkgNameSuffix = 'en.nhentai.com'
extClass = '.NHentaiCom'
extVersionCode = 1
pkgNameSuffix = 'all.nhentaicom'
extClass = '.NHentaiComFactory'
extVersionCode = 2
libVersion = '1.2'
containsNsfw = true
}

View File

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 2.8 KiB

View File

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View File

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 101 KiB

View File

@ -1,14 +1,5 @@
package eu.kanade.tachiyomi.extension.en.nhentai.com
package eu.kanade.tachiyomi.extension.all.nhentaicom
import android.app.Application
import android.content.SharedPreferences
import com.github.salomonbrys.kotson.fromJson
import com.github.salomonbrys.kotson.get
import com.github.salomonbrys.kotson.int
import com.github.salomonbrys.kotson.nullString
import com.github.salomonbrys.kotson.string
import com.google.gson.Gson
import com.google.gson.JsonObject
import eu.kanade.tachiyomi.annotations.Nsfw
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.asObservableSuccess
@ -19,59 +10,87 @@ import eu.kanade.tachiyomi.source.model.Page
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.HttpSource
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import rx.Observable
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import uy.kohesive.injekt.injectLazy
@Nsfw
class NHentaiCom : HttpSource() {
class NHentaiCom(override val lang: String) : HttpSource() {
override val name = "nHentai.com (unoriginal)"
override val name = when (lang) {
"other" -> "nHentai.com (unoriginal)(Text Cleaned)"
"all" -> "nHentai.com (unoriginal)(Unfiltered)"
else -> "nHentai.com (unoriginal)"
}
override val id = when (lang) {
"en" -> 5591830863732393712
else -> super.id
}
override val baseUrl = "https://nhentai.com"
override val lang = "en"
private val langId = toLangId(lang)
override val supportsLatest = true
private val json: Json by injectLazy()
private fun toLangId(langCode: String): String {
return when (langCode) {
"en" -> "1"
"zh" -> "2"
"ja" -> "3"
"other" -> "4"
"cz" -> "5"
"ar" -> "6"
"sk" -> "7"
"eo" -> "8"
else -> ""
}
}
override fun headersBuilder(): Headers.Builder = Headers.Builder()
.add("User-Agent", "Mozilla/5.0 (Windows NT 6.3; WOW64)")
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
override val client: OkHttpClient = network.cloudflareClient
private val gson = Gson()
private fun parseMangaFromJson(response: Response): MangasPage {
val jsonObject = gson.fromJson<JsonObject>(response.body!!.string())
val jsonRaw = response.body!!.string()
val jsonResult = json.parseToJsonElement(jsonRaw).jsonObject
val mangas = jsonObject["data"].asJsonArray.map { json ->
val mangas = jsonResult["data"]!!.jsonArray.map { jsonEl ->
SManga.create().apply {
title = json["title"].string
thumbnail_url = json["image_url"].string
url = json["slug"].string
val jsonObj = jsonEl.jsonObject
title = jsonObj["title"]!!.jsonPrimitive.content
thumbnail_url = jsonObj["image_url"]!!.jsonPrimitive.content
url = jsonObj["slug"]!!.jsonPrimitive.content
}
}
return MangasPage(mangas, jsonObject["current_page"].int < jsonObject["last_page"].int)
return MangasPage(mangas, jsonResult["current_page"]!!.jsonPrimitive.content.toInt() < jsonResult["last_page"]!!.jsonPrimitive.content.toInt())
}
private fun getMangaUrl(url: String): String {
return url.toHttpUrlOrNull()!!.newBuilder()
.setQueryParameter("nsfw", "false").toString()
private fun getMangaUrl(page: Int, sort: String): String {
val url = "$baseUrl/api/comics".toHttpUrlOrNull()!!.newBuilder()
if (langId.isNotBlank()) {
url.setQueryParameter("languages[]", langId)
}
url.setQueryParameter("page", "$page")
url.setQueryParameter("sort", sort)
url.setQueryParameter("nsfw", "false")
return url.toString()
}
// Popular
override fun popularMangaRequest(page: Int): Request {
return GET(getMangaUrl("$baseUrl/api/comics?page=$page&q=&sort=popularity&order=desc&duration=week"), headers)
return GET(getMangaUrl(page, "popularity"), headers)
}
override fun popularMangaParse(response: Response): MangasPage = parseMangaFromJson(response)
@ -79,7 +98,7 @@ class NHentaiCom : HttpSource() {
// Latest
override fun latestUpdatesRequest(page: Int): Request {
return GET(getMangaUrl("$baseUrl/api/comics?page=$page&q=&sort=uploaded_at&order=desc&duration=day"), headers)
return GET(getMangaUrl(page, "uploaded_at"), headers)
}
override fun latestUpdatesParse(response: Response): MangasPage = parseMangaFromJson(response)
@ -90,14 +109,20 @@ class NHentaiCom : HttpSource() {
val url = "$baseUrl/api/comics".toHttpUrlOrNull()!!.newBuilder()
.addQueryParameter("per_page", "18")
.addQueryParameter("page", page.toString())
.addQueryParameter("order", "desc")
.addQueryParameter("q", query)
.addQueryParameter("nsfw", "false")
if (langId.isNotBlank()) {
url.setQueryParameter("languages[]", langId)
}
url.setQueryParameter("page", "$page")
url.setQueryParameter("nsfw", "false")
filters.forEach { filter ->
when (filter) {
is SortFilter -> url.addQueryParameter("sort", filter.toUriPart())
is DurationFilter -> url.addQueryParameter("duration", filter.toUriPart())
is SortOrderFilter -> url.addQueryParameter("order", filter.toUriPart())
}
}
return GET(url.toString(), headers)
@ -113,32 +138,26 @@ class NHentaiCom : HttpSource() {
.map { mangaDetailsParse(it).apply { initialized = true } }
// Return the real URL for "Open in browser"
override fun mangaDetailsRequest(manga: SManga) = GET(getMangaUrl("$baseUrl/en/webtoon/${manga.url}"), headers)
override fun mangaDetailsRequest(manga: SManga) = GET("$baseUrl/en/comic/${manga.url}", headers)
private fun apiMangaDetailsRequest(manga: SManga): Request {
return GET(getMangaUrl("$baseUrl/api/comics/${manga.url}"), headers)
return GET("$baseUrl/api/comics/${manga.url}", headers)
}
override fun mangaDetailsParse(response: Response): SManga {
val jsonObject = gson.fromJson<JsonObject>(response.body!!.string())
val jsonRaw = response.body!!.string()
val jsonObject = json.parseToJsonElement(jsonRaw).jsonObject
return SManga.create().apply {
description = jsonObject["description"].nullString
status = jsonObject["status"].nullString.toStatus()
thumbnail_url = jsonObject["image_url"].nullString
genre = try { jsonObject["tags"].asJsonArray.joinToString { it["name"].string } } catch (_: Exception) { null }
artist = try { jsonObject["artists"].asJsonArray.joinToString { it["name"].string } } catch (_: Exception) { null }
author = try { jsonObject["authors"].asJsonArray.joinToString { it["name"].string } } catch (_: Exception) { null }
description = jsonObject["description"]!!.jsonPrimitive.content
status = SManga.COMPLETED
thumbnail_url = jsonObject["image_url"]!!.jsonPrimitive.content
genre = runCatching{ jsonObject["tags"]!!.jsonArray.joinToString { it.jsonObject["name"]!!.jsonPrimitive.content }}.getOrNull()
artist = runCatching{ jsonObject["artists"]!!.jsonArray.joinToString { it.jsonObject["name"]!!.jsonPrimitive.content }}.getOrNull()
author = runCatching{ jsonObject["authors"]!!.jsonArray.joinToString { it.jsonObject["name"]!!.jsonPrimitive.content }}.getOrNull()
}
}
private fun String?.toStatus() = when {
this == null -> SManga.UNKNOWN
this.contains("ongoing", ignoreCase = true) -> SManga.ONGOING
this.contains("complete", ignoreCase = true) -> SManga.COMPLETED
else -> SManga.UNKNOWN
}
// Chapters
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
@ -159,12 +178,13 @@ class NHentaiCom : HttpSource() {
// Pages
override fun pageListRequest(chapter: SChapter): Request {
return GET(getMangaUrl("$baseUrl/api/comics/${chapter.url}/images"), headers)
return GET("$baseUrl/api/comics/${chapter.url}/images", headers)
}
override fun pageListParse(response: Response): List<Page> {
return gson.fromJson<JsonObject>(response.body!!.string())["images"].asJsonArray.mapIndexed { i, json ->
Page(i, "", json["source_url"].string)
return json.parseToJsonElement(response.body!!.string()).jsonObject["images"]!!.jsonArray.mapIndexed { i, jsonEl ->
val jsonObj = jsonEl.jsonObject
Page(i, "", jsonObj["source_url"]!!.jsonPrimitive.content)
}
}
@ -174,18 +194,26 @@ class NHentaiCom : HttpSource() {
override fun getFilterList() = FilterList(
DurationFilter(getDurationList()),
SortFilter(getSortList())
SortFilter(getSortList()),
SortOrderFilter(getSortOrder())
)
private class DurationFilter(pairs: Array<Pair<String, String>>) : UriPartFilter("Duration", pairs)
private class SortFilter(pairs: Array<Pair<String, String>>) : UriPartFilter("Sorted by", pairs)
private class SortOrderFilter(pairs: Array<Pair<String, String>>) : UriPartFilter("Order", pairs)
open class UriPartFilter(displayName: String, private val vals: Array<Pair<String, String>>) :
Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
fun toUriPart() = vals[state].second
}
private fun getSortOrder() = arrayOf(
Pair("Descending", "desc"),
Pair("Ascending", "asc"),
)
private fun getDurationList() = arrayOf(
Pair("All time", "all"),
Pair("Year", "year"),
@ -195,7 +223,10 @@ class NHentaiCom : HttpSource() {
)
private fun getSortList() = arrayOf(
Pair("Upload date", "uploaded_at"),
Pair("Title", "title"),
Pair("Pages", "pages"),
Pair("Favorites", "favorites"),
Pair("Popularity", "popularity"),
Pair("Date", "uploaded_at")
)
}

View File

@ -0,0 +1,14 @@
package eu.kanade.tachiyomi.extension.all.nhentaicom
import eu.kanade.tachiyomi.annotations.Nsfw
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceFactory
@Nsfw
class NHentaiComFactory : SourceFactory {
override fun createSources(): List<Source> = languages.map { NHentaiCom(it) }
}
private val languages = listOf(
"all", "en", "zh", "ja", "other", "eo", "cz", "ar", "sk"
)