add NineHentai very basic features (#829)

* add NineHentai very basic features

* icons
This commit is contained in:
Carlos 2019-02-20 09:09:12 -05:00 committed by GitHub
parent b3167bc1a9
commit 27419ab711
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 245 additions and 1 deletions

View File

@ -5,7 +5,7 @@ buildscript {
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.3.0'
classpath 'com.android.tools.build:gradle:3.3.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}

View File

@ -0,0 +1,16 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
ext {
appName = 'Tachiyomi: NineHentai'
pkgNameSuffix = 'all.ninehentai'
extClass = '.NineHentai'
extVersionCode = 1
libVersion = '1.2'
}
dependencies {
compileOnly 'com.google.code.gson:gson:2.8.2'
compileOnly 'com.github.salomonbrys.kotson:kotson:2.5.0'
compileOnly 'com.github.inorichi.injekt:injekt-core:65b0440'
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

View File

@ -0,0 +1,5 @@
package eu.kanade.tachiyomi.extension.all.ninehentai
data class id(
val id : Int
)

View File

@ -0,0 +1,223 @@
package eu.kanade.tachiyomi.extension.all.ninehentai
import com.github.salomonbrys.kotson.get
import com.github.salomonbrys.kotson.int
import com.github.salomonbrys.kotson.string
import com.google.gson.Gson
import com.google.gson.JsonElement
import com.google.gson.JsonParser
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.source.model.*
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import okhttp3.*
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import rx.Observable
import java.net.URLEncoder
import java.util.*
open class NineHentai() : ParsedHttpSource() {
final override val baseUrl = "https://9hentai.com"
override val name = "NineHentai"
override val lang = "en"
override val supportsLatest = true
override val client: OkHttpClient = network.cloudflareClient
override fun popularMangaRequest(page: Int): Request {
return POST(baseUrl + SEARCH_URL, headers, buildRequestBody(page = page, sort = 1))
}
override fun latestUpdatesRequest(page: Int): Request {
return POST(baseUrl + SEARCH_URL, headers, buildRequestBody(page = page))
}
override fun fetchPopularManga(page: Int): Observable<MangasPage> {
return client.newCall(popularMangaRequest(page))
.asObservableSuccess()
.map { response ->
popularMangaParse(response)
}
}
override fun popularMangaParse(response: Response): MangasPage {
val list = getMangaList(response)
return MangasPage(list, false)
}
override fun fetchLatestUpdates(page: Int): Observable<MangasPage> {
return client.newCall(latestUpdatesRequest(page))
.asObservableSuccess()
.map { response ->
latestUpdatesParse(response)
}
}
override fun latestUpdatesParse(response: Response): MangasPage = popularMangaParse(response)
private fun getMangaList(response: Response): List<SManga> {
val jsonData = response.body()!!.string()
val jsonObject = JsonParser().parse(jsonData).asJsonObject
val results = jsonObject.getAsJsonArray("results")
return parseSearch(results.toList())
}
private fun parseSearch(jsonArray: List<JsonElement>): List<SManga> {
val mutableList = mutableListOf<SManga>()
jsonArray.forEach { json ->
val manga = SManga.create()
val id = json["id"].string
manga.url = "$baseUrl/g/$id"
manga.title = json["title"].string
manga.thumbnail_url = json["image_server"].string + id + "/" + "cover.jpg"
mutableList.add(manga)
}
return mutableList
}
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
return client.newCall(mangaDetailsRequest(manga))
.asObservableSuccess()
.map { response ->
chapterListParse(response)
}
}
private fun getChapter(response: Response): SChapter {
val jsonData = response.body()!!.string()
val jsonObject = JsonParser().parse(jsonData).asJsonObject
val jsonArray = jsonObject.getAsJsonObject("results")
val sChapter = SChapter.create()
jsonArray.let { json ->
val id = json["id"].string
sChapter.url = "$baseUrl/g/$id"
sChapter.name = "chapter"
//api doesnt return date so setting to current date for now
sChapter.date_upload = Date().time
}
return sChapter
}
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
return POST(baseUrl + SEARCH_URL, headers, buildRequestBody(query, page))
}
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
return client.newCall(searchMangaRequest(page, query, filters))
.asObservableSuccess()
.map { response ->
searchMangaParse(response)
}
}
override fun searchMangaParse(response: Response): MangasPage = popularMangaParse(response)
override fun mangaDetailsParse(response: Response): SManga {
val jsonData = response.body()!!.string()
val jsonObject = JsonParser().parse(jsonData).asJsonObject
val results = jsonObject.getAsJsonObject("results")
return parseSearch(listOf(results))[0]
}
override fun chapterListParse(response: Response): List<SChapter> = listOf(getChapter(response))
override fun pageListParse(document: Document) = throw Exception("Not used")
override fun fetchPageList(chapter: SChapter): Observable<List<Page>> {
val mangaId = chapter.url.substringAfter("/g/").toInt()
return client.newCall(POST(baseUrl + MANGA_URL, headers, buildIdBody(mangaId)))
.asObservableSuccess()
.map { response ->
pageListParse(response)
}
}
override fun pageListParse(response: Response): List<Page> {
val jsonData = response.body()!!.string()
val jsonObject = JsonParser().parse(jsonData).asJsonObject
val jsonArray = jsonObject.getAsJsonObject("results")
var imageUrl: String
var totalPages: Int
var mangaId: String
jsonArray.let { json ->
mangaId = json["id"].string
imageUrl = json["image_server"].string + mangaId + "/"
totalPages = json["total_page"].int
}
val pages = mutableListOf<Page>()
for (i in 1..totalPages) {
pages.add(Page(pages.size, "", "$imageUrl$i.jpg"))
}
return pages
}
private fun buildRequestBody(searchText: String = "", page: Int = 0, sort: Int = 0): RequestBody {
//in the future switch this to dtos and actually build the json. This is just a work around for
//initial release, then you can have actual tag searching etc
var json = """{"search":{"text":"","page":0,"sort":0,"pages":{"range":[0,2000]},"tag":{"text":"","type":1,"tags":[],"items":{"included":[],"excluded":[]}}}}"""
if (searchText.isNotEmpty()) {
val encodedSearch = URLEncoder.encode(searchText, "UTF-8")
json = json.replaceFirst(""""text":""""", """"text":"$encodedSearch"""")
}
if (page > 0) {
json = json.replaceFirst(""""page":0""", """"page":$page""")
}
if (sort > 0) {
json = json.replaceFirst(""""sort":0""", """"sort":$sort""")
}
return RequestBody.create(MEDIA_TYPE, json)
}
override fun mangaDetailsRequest(smanga: SManga): Request {
val id = smanga.url.substringAfter("/g/").toInt()
return POST(baseUrl + MANGA_URL, headers, buildIdBody(id))
}
private fun buildIdBody(id: Int): RequestBody {
val dto = eu.kanade.tachiyomi.extension.all.ninehentai.id(id)
return RequestBody.create(MEDIA_TYPE, Gson().toJson(dto))
}
override fun imageUrlParse(document: Document): String = ""
override fun chapterFromElement(element: Element): SChapter = throw Exception("Not used")
override fun chapterListSelector(): String = throw Exception("Not used")
override fun latestUpdatesFromElement(element: Element): SManga = throw Exception("Not used")
override fun latestUpdatesNextPageSelector(): String? = throw Exception("Not used")
override fun latestUpdatesSelector(): String = throw Exception("Not used")
override fun mangaDetailsParse(document: Document): SManga = throw Exception("Not used")
override fun popularMangaFromElement(element: Element): SManga = throw Exception("Not used")
override fun popularMangaNextPageSelector(): String? = throw Exception("Not used")
override fun popularMangaSelector(): String = throw Exception("Not used")
override fun searchMangaFromElement(element: Element): SManga = throw Exception("Not used")
override fun searchMangaNextPageSelector(): String? = throw Exception("Not used")
override fun searchMangaSelector(): String = throw Exception("Not used")
companion object {
private val MEDIA_TYPE = MediaType.parse("application/json; charset=utf-8")
private const val SEARCH_URL = "/api/getBook"
private const val MANGA_URL = "/api/getBookByID"
}
}