E-Hentai: switch to SourceFactory

This commit is contained in:
Eugene 2019-10-27 15:24:12 -04:00
parent 40c5cb33aa
commit 170c382b15
No known key found for this signature in database
GPG Key ID: E1FD745328866B0A
6 changed files with 145 additions and 152 deletions

View File

@ -4,8 +4,8 @@ apply plugin: 'kotlin-android'
ext { 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; .EHPortuguese; .EHRussian; .EHSpanish; .EHThai; .EHVietnamese; .EHSpeechless; .EHOther' extClass = '.EHFactory'
extVersionCode = 6 extVersionCode = 7
libVersion = '1.2' libVersion = '1.2'
} }

View File

@ -0,0 +1,26 @@
package eu.kanade.tachiyomi.extension.all.ehentai
import eu.kanade.tachiyomi.source.Source
import eu.kanade.tachiyomi.source.SourceFactory
class EHFactory : SourceFactory {
override fun createSources(): List<Source> = listOf(
EHentai("ja", "japanese"),
EHentai("en", "english"),
EHentai("zh", "chinese"),
EHentai("nl", "dutch"),
EHentai("fr", "french"),
EHentai("de", "german"),
EHentai("hu", "hungarian"),
EHentai("it", "italian"),
EHentai("ko", "korean"),
EHentai("pl", "polish"),
EHentai("pt", "portuguese"),
EHentai("ru", "russian"),
EHentai("es", "spanish"),
EHentai("th", "thai"),
EHentai("vi", "vietnamese"),
EHentai("none", "n/a"),
EHentai("other", "other")
)
}

View File

@ -1,42 +0,0 @@
package eu.kanade.tachiyomi.extension.all.ehentai
/**
* E-Hentai languages
*/
class EHJapanese : EHentai("ja", "japanese")
class EHEnglish : EHentai("en", "english")
class EHChinese : EHentai("zh", "chinese")
class EHDutch : EHentai("nl", "dutch")
class EHFrench : EHentai("fr", "french")
class EHGerman : EHentai("de", "german")
class EHHungarian : EHentai("hu", "hungarian")
class EHItalian : EHentai("it", "italian")
class EHKorean : EHentai("ko", "korean")
class EHPolish : EHentai("pl", "polish")
class EHPortuguese : EHentai("pt", "portuguese")
class EHRussian : EHentai("ru", "russian")
class EHSpanish : EHentai("es", "spanish")
class EHThai : EHentai("th", "thai")
class EHVietnamese : EHentai("vi", "vietnamese")
class EHSpeechless : EHentai("none", "n/a")
class EHOther : EHentai("other", "other")
fun getAllEHentaiLanguages() = listOf(
EHJapanese(),
EHEnglish(),
EHChinese(),
EHDutch(),
EHFrench(),
EHGerman(),
EHHungarian(),
EHItalian(),
EHKorean(),
EHPolish(),
EHPortuguese(),
EHRussian(),
EHSpanish(),
EHThai(),
EHVietnamese(),
EHSpeechless(),
EHOther()
)

View File

@ -3,10 +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.* import okhttp3.CacheControl
import okhttp3.CookieJar
import okhttp3.Headers
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import rx.Observable import rx.Observable
import java.net.URLEncoder import java.net.URLEncoder
@ -31,7 +40,7 @@ open class EHentai(override val lang: String, private val ehLang: String) : Http
//Get image //Get image
it.parent().select(".glthumb img")?.first().apply { it.parent().select(".glthumb img")?.first().apply {
thumbnail_url = this?.attr("data-src")?.nullIfBlank() thumbnail_url = this?.attr("data-src")?.nullIfBlank()
?: this?.attr("src") ?: this?.attr("src")
} }
} }
} }
@ -140,46 +149,46 @@ open class EHentai(override val lang: String, private val ehLang: String) : Http
//Parse the table //Parse the table
select("#gdd tr").forEach { select("#gdd tr").forEach {
it.select(".gdt1") it.select(".gdt1")
.text() .text()
.nullIfBlank() .nullIfBlank()
?.trim() ?.trim()
?.let { left -> ?.let { left ->
it.select(".gdt2") it.select(".gdt2")
.text() .text()
.nullIfBlank() .nullIfBlank()
?.trim() ?.trim()
?.let { right -> ?.let { right ->
ignore { ignore {
when (left.removeSuffix(":") when (left.removeSuffix(":")
.toLowerCase()) { .toLowerCase()) {
"posted" -> datePosted = EX_DATE_FORMAT.parse(right).time "posted" -> datePosted = EX_DATE_FORMAT.parse(right).time
"visible" -> visible = right.nullIfBlank() "visible" -> visible = right.nullIfBlank()
"language" -> { "language" -> {
language = right.removeSuffix(TR_SUFFIX).trim().nullIfBlank() language = right.removeSuffix(TR_SUFFIX).trim().nullIfBlank()
translated = right.endsWith(TR_SUFFIX, true) translated = right.endsWith(TR_SUFFIX, true)
}
"file size" -> size = parseHumanReadableByteCount(right)?.toLong()
"length" -> length = right.removeSuffix("pages").trim().nullIfBlank()?.toInt()
"favorited" -> favorites = right.removeSuffix("times").trim().nullIfBlank()?.toInt()
}
} }
"file size" -> size = parseHumanReadableByteCount(right)?.toLong()
"length" -> length = right.removeSuffix("pages").trim().nullIfBlank()?.toInt()
"favorited" -> favorites = right.removeSuffix("times").trim().nullIfBlank()?.toInt()
} }
} }
}
}
} }
//Parse ratings //Parse ratings
ignore { ignore {
averageRating = select("#rating_label") averageRating = select("#rating_label")
.text() .text()
.removePrefix("Average:") .removePrefix("Average:")
.trim() .trim()
.nullIfBlank() .nullIfBlank()
?.toDouble() ?.toDouble()
ratingCount = select("#rating_count") ratingCount = select("#rating_count")
.text() .text()
.trim() .trim()
.nullIfBlank() .nullIfBlank()
?.toInt() ?.toInt()
} }
//Parse tags //Parse tags
@ -188,7 +197,7 @@ open class EHentai(override val lang: String, private val ehLang: String) : Http
val namespace = it.select(".tc").text().removeSuffix(":") val namespace = it.select(".tc").text().removeSuffix(":")
val currentTags = it.select("div").map { val currentTags = it.select("div").map {
Tag(it.text().trim(), Tag(it.text().trim(),
it.hasClass("gtl")) it.hasClass("gtl"))
} }
tags[namespace] = currentTags tags[namespace] = currentTags
} }
@ -205,8 +214,8 @@ open class EHentai(override val lang: String, private val ehLang: String) : Http
override fun pageListParse(response: Response) = throw UnsupportedOperationException("Unused method was called somehow!") override fun pageListParse(response: Response) = throw UnsupportedOperationException("Unused method was called somehow!")
override fun fetchImageUrl(page: Page) = client.newCall(imageUrlRequest(page)) override fun fetchImageUrl(page: Page) = client.newCall(imageUrlRequest(page))
.asObservableSuccess() .asObservableSuccess()
.map { realImageUrlParse(it, page) }!! .map { realImageUrlParse(it, page) }!!
private fun realImageUrlParse(response: Response, page: Page) = with(response.asJsoup()) { private fun realImageUrlParse(response: Response, page: Page) = with(response.asJsoup()) {
val currentImage = getElementById("img").attr("src") val currentImage = getElementById("img").attr("src")
@ -231,8 +240,8 @@ open class EHentai(override val lang: String, private val ehLang: String) : Http
//Exclude every other language except the one we have selected //Exclude every other language except the one we have selected
settings += "xl_" + languageMappings.filter { it.first != ehLang } settings += "xl_" + languageMappings.filter { it.first != ehLang }
.flatMap { it.second } .flatMap { it.second }
.joinToString("x") .joinToString("x")
cookies["uconfig"] = buildSettings(settings) cookies["uconfig"] = buildSettings(settings)
@ -252,27 +261,27 @@ open class EHentai(override val lang: String, private val ehLang: String) : Http
} }
private fun addParam(url: String, param: String, value: String) = Uri.parse(url) private fun addParam(url: String, param: String, value: String) = Uri.parse(url)
.buildUpon() .buildUpon()
.appendQueryParameter(param, value) .appendQueryParameter(param, value)
.toString() .toString()
override val client = network.client.newBuilder() override val client = network.client.newBuilder()
.cookieJar(CookieJar.NO_COOKIES) .cookieJar(CookieJar.NO_COOKIES)
.addInterceptor { chain -> .addInterceptor { chain ->
val newReq = chain val newReq = chain
.request() .request()
.newBuilder() .newBuilder()
.removeHeader("Cookie") .removeHeader("Cookie")
.addHeader("Cookie", cookiesHeader) .addHeader("Cookie", cookiesHeader)
.build() .build()
chain.proceed(newReq) chain.proceed(newReq)
}.build()!! }.build()!!
//Filters //Filters
override fun getFilterList() = FilterList( override fun getFilterList() = FilterList(
GenreGroup(), GenreGroup(),
AdvancedGroup() AdvancedGroup()
) )
class GenreOption(name: String, private val genreId: String) : Filter.CheckBox(name, false), UriFilter { class GenreOption(name: String, private val genreId: String) : Filter.CheckBox(name, false), UriFilter {
@ -282,16 +291,16 @@ open class EHentai(override val lang: String, private val ehLang: String) : Http
} }
class GenreGroup : UriGroup<GenreOption>("Genres", listOf( class GenreGroup : UriGroup<GenreOption>("Genres", listOf(
GenreOption("Dōjinshi", "doujinshi"), GenreOption("Dōjinshi", "doujinshi"),
GenreOption("Manga", "manga"), GenreOption("Manga", "manga"),
GenreOption("Artist CG", "artistcg"), GenreOption("Artist CG", "artistcg"),
GenreOption("Game CG", "gamecg"), GenreOption("Game CG", "gamecg"),
GenreOption("Western", "western"), GenreOption("Western", "western"),
GenreOption("Non-H", "non-h"), GenreOption("Non-H", "non-h"),
GenreOption("Image Set", "imageset"), GenreOption("Image Set", "imageset"),
GenreOption("Cosplay", "cosplay"), GenreOption("Cosplay", "cosplay"),
GenreOption("Asian Porn", "asianporn"), GenreOption("Asian Porn", "asianporn"),
GenreOption("Misc", "misc") GenreOption("Misc", "misc")
)) ))
class AdvancedOption(name: String, private val param: String, defValue: Boolean = false) : Filter.CheckBox(name, defValue), UriFilter { class AdvancedOption(name: String, private val param: String, defValue: Boolean = false) : Filter.CheckBox(name, defValue), UriFilter {
@ -302,11 +311,11 @@ open class EHentai(override val lang: String, private val ehLang: String) : Http
} }
class RatingOption : Filter.Select<String>("Minimum Rating", arrayOf( class RatingOption : Filter.Select<String>("Minimum Rating", arrayOf(
"Any", "Any",
"2 stars", "2 stars",
"3 stars", "3 stars",
"4 stars", "4 stars",
"5 stars" "5 stars"
)), UriFilter { )), UriFilter {
override fun addToUri(builder: Uri.Builder) { override fun addToUri(builder: Uri.Builder) {
if (state > 0) builder.appendQueryParameter("f_srdd", (state + 1).toString()) if (state > 0) builder.appendQueryParameter("f_srdd", (state + 1).toString())
@ -314,37 +323,37 @@ open class EHentai(override val lang: String, private val ehLang: String) : Http
} }
//Explicit type arg for listOf() to workaround this: KT-16570 //Explicit type arg for listOf() to workaround this: KT-16570
class AdvancedGroup : UriGroup<Filter<*>>("Advanced Options", listOf<Filter<*>>( class AdvancedGroup : UriGroup<Filter<*>>("Advanced Options", listOf(
AdvancedOption("Search Gallery Name", "f_sname", true), AdvancedOption("Search Gallery Name", "f_sname", true),
AdvancedOption("Search Gallery Tags", "f_stags", true), AdvancedOption("Search Gallery Tags", "f_stags", true),
AdvancedOption("Search Gallery Description", "f_sdesc"), AdvancedOption("Search Gallery Description", "f_sdesc"),
AdvancedOption("Search Torrent Filenames", "f_storr"), AdvancedOption("Search Torrent Filenames", "f_storr"),
AdvancedOption("Only Show Galleries With Torrents", "f_sto"), AdvancedOption("Only Show Galleries With Torrents", "f_sto"),
AdvancedOption("Search Low-Power Tags", "f_sdt1"), AdvancedOption("Search Low-Power Tags", "f_sdt1"),
AdvancedOption("Search Downvoted Tags", "f_sdt2"), AdvancedOption("Search Downvoted Tags", "f_sdt2"),
AdvancedOption("Show Expunged Galleries", "f_sh"), AdvancedOption("Show Expunged Galleries", "f_sh"),
RatingOption() RatingOption()
)) ))
//map languages to their internal ids //map languages to their internal ids
private val languageMappings = listOf( private val languageMappings = listOf(
Pair("japanese", listOf("0", "1024", "2048")), Pair("japanese", listOf("0", "1024", "2048")),
Pair("english", listOf("1", "1025", "2049")), Pair("english", listOf("1", "1025", "2049")),
Pair("chinese", listOf("10", "1034", "2058")), Pair("chinese", listOf("10", "1034", "2058")),
Pair("dutch", listOf("20", "1044", "2068")), Pair("dutch", listOf("20", "1044", "2068")),
Pair("french", listOf("30", "1054", "2078")), Pair("french", listOf("30", "1054", "2078")),
Pair("german", listOf("40", "1064", "2088")), Pair("german", listOf("40", "1064", "2088")),
Pair("hungarian", listOf("50", "1074", "2098")), Pair("hungarian", listOf("50", "1074", "2098")),
Pair("italian", listOf("60", "1084", "2108")), Pair("italian", listOf("60", "1084", "2108")),
Pair("korean", listOf("70", "1094", "2118")), Pair("korean", listOf("70", "1094", "2118")),
Pair("polish", listOf("80", "1104", "2128")), Pair("polish", listOf("80", "1104", "2128")),
Pair("portuguese", listOf("90", "1114", "2138")), Pair("portuguese", listOf("90", "1114", "2138")),
Pair("russian", listOf("100", "1124", "2148")), Pair("russian", listOf("100", "1124", "2148")),
Pair("spanish", listOf("110", "1134", "2158")), Pair("spanish", listOf("110", "1134", "2158")),
Pair("thai", listOf("120", "1144", "2168")), Pair("thai", listOf("120", "1144", "2168")),
Pair("vietnamese", listOf("130", "1154", "2178")), Pair("vietnamese", listOf("130", "1154", "2178")),
Pair("n/a", listOf("254", "1278", "2302")), Pair("n/a", listOf("254", "1278", "2302")),
Pair("other", listOf("255", "1279", "2303")) Pair("other", listOf("255", "1279", "2303"))
) )
companion object { companion object {

View File

@ -2,15 +2,16 @@ package eu.kanade.tachiyomi.extension.all.ehentai
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import java.text.SimpleDateFormat import java.text.SimpleDateFormat
import java.util.* import java.util.Date
import java.util.Locale
private const val EH_ARTIST_NAMESPACE = "artist" private const val EH_ARTIST_NAMESPACE = "artist"
private const val EH_AUTHOR_NAMESPACE = "author" private const val EH_AUTHOR_NAMESPACE = "author"
private val ONGOING_SUFFIX = arrayOf( private val ONGOING_SUFFIX = arrayOf(
"[ongoing]", "[ongoing]",
"(ongoing)", "(ongoing)",
"{ongoing}" "{ongoing}"
) )
val EX_DATE_FORMAT = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.US) val EX_DATE_FORMAT = SimpleDateFormat("yyyy-MM-dd HH:mm", Locale.US)
@ -37,8 +38,8 @@ fun ExGalleryMetadata.copyTo(manga: SManga) {
manga.status = SManga.COMPLETED manga.status = SManga.COMPLETED
title?.let { t -> title?.let { t ->
if (ONGOING_SUFFIX.any { if (ONGOING_SUFFIX.any {
t.endsWith(it, ignoreCase = true) t.endsWith(it, ignoreCase = true)
}) manga.status = SManga.ONGOING }) manga.status = SManga.ONGOING
} }
//Build a nice looking description out of what we know //Build a nice looking description out of what we know
@ -67,8 +68,8 @@ fun ExGalleryMetadata.copyTo(manga: SManga) {
val tagsDesc = buildTagsDescription(this) val tagsDesc = buildTagsDescription(this)
manga.description = listOf(titleDesc.toString(), detailsDesc.toString(), tagsDesc.toString()) manga.description = listOf(titleDesc.toString(), detailsDesc.toString(), tagsDesc.toString())
.filter(String::isNotBlank) .filter(String::isNotBlank)
.joinToString(separator = "\n") .joinToString(separator = "\n")
} }
private fun buildTagsDescription(metadata: ExGalleryMetadata) = StringBuilder("Tags:\n").apply { private fun buildTagsDescription(metadata: ExGalleryMetadata) = StringBuilder("Tags:\n").apply {

View File

@ -1,7 +1,6 @@
package eu.kanade.tachiyomi.extension.all.ehentai; package eu.kanade.tachiyomi.extension.all.ehentai
/** /**
* Simple tag model * Simple tag model
*/ */
data class Tag(val name: String, val light: Boolean)
data class Tag(val name: String, val light: Boolean)