Port E-Hentai from ilwaz/TachiyomiEH (closes #960)
This commit is contained in:
parent
3c41ee7dea
commit
3014f5b3f6
@ -5,7 +5,7 @@ ext {
|
|||||||
appName = 'Tachiyomi: E-Hentai'
|
appName = 'Tachiyomi: E-Hentai'
|
||||||
pkgNameSuffix = 'all.ehentai'
|
pkgNameSuffix = 'all.ehentai'
|
||||||
extClass = '.EHJapanese; .EHEnglish; .EHChinese; .EHDutch; .EHFrench; .EHGerman; .EHHungarian; .EHItalian; .EHKorean; .EHPolish; .EHPolish; .EHPortuguese; .EHRussian; .EHSpanish; .EHThai; .EHVietnamese; .EHSpeechless; .EHOther'
|
extClass = '.EHJapanese; .EHEnglish; .EHChinese; .EHDutch; .EHFrench; .EHGerman; .EHHungarian; .EHItalian; .EHKorean; .EHPolish; .EHPolish; .EHPortuguese; .EHRussian; .EHSpanish; .EHThai; .EHVietnamese; .EHSpeechless; .EHOther'
|
||||||
extVersionCode = 2
|
extVersionCode = 3
|
||||||
libVersion = '1.2'
|
libVersion = '1.2'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,14 +3,19 @@ package eu.kanade.tachiyomi.extension.all.ehentai
|
|||||||
import android.net.Uri
|
import android.net.Uri
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||||
import eu.kanade.tachiyomi.source.model.*
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
|
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 eu.kanade.tachiyomi.source.online.HttpSource
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import okhttp3.CacheControl
|
import okhttp3.CacheControl
|
||||||
|
import okhttp3.CookieJar
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import org.jsoup.nodes.Document
|
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
import java.net.URLEncoder
|
import java.net.URLEncoder
|
||||||
@ -23,47 +28,37 @@ open class EHentai(override val lang: String, val ehLang: String) : HttpSource()
|
|||||||
|
|
||||||
override val supportsLatest = true
|
override val supportsLatest = true
|
||||||
|
|
||||||
/**
|
|
||||||
* Gallery list entry
|
|
||||||
* @param fav The favorite this gallery belongs to (currently unused)
|
|
||||||
* @param manga The manga object
|
|
||||||
*/
|
|
||||||
data class ParsedManga(val fav: String?, val manga: SManga)
|
|
||||||
|
|
||||||
fun extendedGenericMangaParse(doc: Document)
|
val initMetaRegex = """inits?~(?:ul\.)?(.*?)~(.*?)~""".toRegex()
|
||||||
= with(doc) {
|
|
||||||
//Parse mangas
|
fun parseInitsMeta(meta: String): String{
|
||||||
val parsedMangas = select(".gtr0,.gtr1").map {
|
val match = initMetaRegex.find(meta)
|
||||||
ParsedManga(
|
return "https://" + match?.groupValues?.get(1) +"/"+ match?.groupValues?.get(2)
|
||||||
fav = it.select(".itd .it3 > .i[id]").attr("title"),
|
}
|
||||||
manga = SManga.create().apply {
|
|
||||||
|
private fun genericMangaParse(response: Response): MangasPage {
|
||||||
|
val doc = response.asJsoup()
|
||||||
|
val parsedMangas = doc.select("table.itg td.glname").map {
|
||||||
|
SManga.create().apply {
|
||||||
//Get title
|
//Get title
|
||||||
it.select(".itd .it5 a").apply {
|
it.select("a")?.first()?.apply {
|
||||||
title = text()
|
title = text()
|
||||||
setUrlWithoutDomain(addParam(attr("href"), "nw", "always"))
|
url = ExGalleryMetadata.normalizeUrl(attr("href"))
|
||||||
}
|
}
|
||||||
//Get image
|
//Get image
|
||||||
it.select(".itd .it2").first().apply {
|
it.parent().select(".glthumb")?.first().apply {
|
||||||
children().first()?.let {
|
thumbnail_url = this!!.select("img").first()?.attr("src")?.nullIfBlank()
|
||||||
thumbnail_url = it.attr("src")
|
?: parseInitsMeta(it.parent()
|
||||||
} ?: text().split("~").apply {
|
.select(".glthumb").first()
|
||||||
thumbnail_url = "http://${this[1]}/${this[2]}"
|
.childNode(0).toString())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
//Add to page if required
|
//Add to page if required
|
||||||
val hasNextPage = select("a[onclick=return false]").last()?.text() == ">"
|
val hasNextPage = doc.select("a[onclick=return false]").last()?.text() == ">"
|
||||||
Pair(parsedMangas, hasNextPage)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
return MangasPage(parsedMangas, hasNextPage)
|
||||||
* Parse a list of galleries
|
|
||||||
*/
|
|
||||||
fun genericMangaParse(response: Response)
|
|
||||||
= extendedGenericMangaParse(response.asJsoup()).let {
|
|
||||||
MangasPage(it.first.map { it.manga }, it.second)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>>
|
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>>
|
||||||
@ -85,7 +80,7 @@ open class EHentai(override val lang: String, val ehLang: String) : HttpSource()
|
|||||||
*/
|
*/
|
||||||
private fun fetchChapterPage(chapter: SChapter, np: String,
|
private fun fetchChapterPage(chapter: SChapter, np: String,
|
||||||
pastUrls: List<String> = emptyList()): Observable<List<String>> {
|
pastUrls: List<String> = emptyList()): Observable<List<String>> {
|
||||||
val urls = pastUrls.toMutableList()
|
val urls = ArrayList(pastUrls)
|
||||||
return chapterPageCall(np).flatMap {
|
return chapterPageCall(np).flatMap {
|
||||||
val jsoup = it.asJsoup()
|
val jsoup = it.asJsoup()
|
||||||
urls += parseChapterPage(jsoup)
|
urls += parseChapterPage(jsoup)
|
||||||
@ -162,15 +157,22 @@ open class EHentai(override val lang: String, val ehLang: String) : HttpSource()
|
|||||||
thumbnailUrl = select("#gd1 div").attr("style").nullIfBlank()?.let {
|
thumbnailUrl = select("#gd1 div").attr("style").nullIfBlank()?.let {
|
||||||
it.substring(it.indexOf('(') + 1 until it.lastIndexOf(')'))
|
it.substring(it.indexOf('(') + 1 until it.lastIndexOf(')'))
|
||||||
}
|
}
|
||||||
|
genre = select("#gdc div").text().nullIfBlank()?.trim()?.toLowerCase()
|
||||||
genre = select(".ic").parents().attr("href").nullIfBlank()?.trim()?.substringAfterLast('/')
|
|
||||||
|
|
||||||
uploader = select("#gdn").text().nullIfBlank()?.trim()
|
uploader = select("#gdn").text().nullIfBlank()?.trim()
|
||||||
|
|
||||||
//Parse the table
|
//Parse the table
|
||||||
select("#gdd tr").forEach {
|
select("#gdd tr").forEach {
|
||||||
val left = it.select(".gdt1").text().nullIfBlank()?.trim() ?: return@forEach
|
it.select(".gdt1")
|
||||||
val right = it.select(".gdt2").text().nullIfBlank()?.trim() ?: return@forEach
|
.text()
|
||||||
|
.nullIfBlank()
|
||||||
|
?.trim()
|
||||||
|
?.let { left ->
|
||||||
|
it.select(".gdt2")
|
||||||
|
.text()
|
||||||
|
.nullIfBlank()
|
||||||
|
?.trim()
|
||||||
|
?.let { right ->
|
||||||
ignore {
|
ignore {
|
||||||
when (left.removeSuffix(":")
|
when (left.removeSuffix(":")
|
||||||
.toLowerCase()) {
|
.toLowerCase()) {
|
||||||
@ -186,16 +188,18 @@ open class EHentai(override val lang: String, val ehLang: String) : HttpSource()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//Parse ratings
|
//Parse ratings
|
||||||
ignore {
|
ignore {
|
||||||
averageRating = getElementById("rating_label")
|
averageRating = select("#rating_label")
|
||||||
.text()
|
.text()
|
||||||
.removePrefix("Average:")
|
.removePrefix("Average:")
|
||||||
.trim()
|
.trim()
|
||||||
.nullIfBlank()
|
.nullIfBlank()
|
||||||
?.toDouble()
|
?.toDouble()
|
||||||
ratingCount = getElementById("rating_count")
|
ratingCount = select("#rating_count")
|
||||||
.text()
|
.text()
|
||||||
.trim()
|
.trim()
|
||||||
.nullIfBlank()
|
.nullIfBlank()
|
||||||
@ -237,7 +241,7 @@ open class EHentai(override val lang: String, val ehLang: String) : HttpSource()
|
|||||||
//TODO We cannot currently do this as page.url is immutable
|
//TODO We cannot currently do this as page.url is immutable
|
||||||
//Each press of the retry button will choose another server
|
//Each press of the retry button will choose another server
|
||||||
/*select("#loadfail").attr("onclick").nullIfBlank()?.let {
|
/*select("#loadfail").attr("onclick").nullIfBlank()?.let {
|
||||||
page.url = addParam(page.url, "nl", it.substring(it.indexOf('\'') + 1 .. it.lastIndexOf('\'') - 1))
|
page.url = addParam(page.url, "nl", it.substring(it.indexOf('\'') + 1 until it.lastIndexOf('\'')))
|
||||||
}*/
|
}*/
|
||||||
currentImage
|
currentImage
|
||||||
}!!
|
}!!
|
||||||
@ -283,10 +287,12 @@ open class EHentai(override val lang: String, val ehLang: String) : HttpSource()
|
|||||||
.toString()
|
.toString()
|
||||||
|
|
||||||
override val client = network.client.newBuilder()
|
override val client = network.client.newBuilder()
|
||||||
.addNetworkInterceptor { chain ->
|
.cookieJar(CookieJar.NO_COOKIES)
|
||||||
|
.addInterceptor { chain ->
|
||||||
val newReq = chain
|
val newReq = chain
|
||||||
.request()
|
.request()
|
||||||
.newBuilder()
|
.newBuilder()
|
||||||
|
.removeHeader("Cookie")
|
||||||
.addHeader("Cookie", cookiesHeader)
|
.addHeader("Cookie", cookiesHeader)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
package eu.kanade.tachiyomi.extension.all.ehentai;
|
package eu.kanade.tachiyomi.extension.all.ehentai;
|
||||||
|
|
||||||
|
import android.net.Uri
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gallery metadata storage model
|
* Gallery metadata storage model
|
||||||
*/
|
*/
|
||||||
@ -28,4 +30,27 @@ class ExGalleryMetadata {
|
|||||||
var uploader: String? = null
|
var uploader: String? = null
|
||||||
|
|
||||||
val tags: MutableMap<String, List<Tag>> = mutableMapOf()
|
val tags: MutableMap<String, List<Tag>> = mutableMapOf()
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private fun splitGalleryUrl(url: String)
|
||||||
|
= url.let {
|
||||||
|
//Only parse URL if is full URL
|
||||||
|
val pathSegments = if(it.startsWith("http"))
|
||||||
|
Uri.parse(it).pathSegments
|
||||||
|
else
|
||||||
|
it.split('/')
|
||||||
|
pathSegments.filterNot(String::isNullOrBlank)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun galleryId(url: String) = splitGalleryUrl(url)[1]
|
||||||
|
|
||||||
|
fun galleryToken(url: String) =
|
||||||
|
splitGalleryUrl(url)[2]
|
||||||
|
|
||||||
|
fun normalizeUrl(id: String, token: String)
|
||||||
|
= "/g/$id/$token/?nw=always"
|
||||||
|
|
||||||
|
fun normalizeUrl(url: String)
|
||||||
|
= normalizeUrl(galleryId(url), galleryToken(url))
|
||||||
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user