From a423ba14ce409719304d2aeb166825673690306a Mon Sep 17 00:00:00 2001 From: vaginadesolator <76472350+vaginadesolator@users.noreply.github.com> Date: Wed, 20 Jan 2021 06:43:41 +0800 Subject: [PATCH] New extension for HentaiHand.com (#5427) * New extension for HentaiHand.com * Set containsNsfw flag as true in build.gradle Co-authored-by: scb261 <65343233+scb261@users.noreply.github.com> * Add @Nsfw annotation Co-authored-by: scb261 <65343233+scb261@users.noreply.github.com> * Add missing nsfw import * Split into language sources * Reimplement ID lookup mechanism using RxJava Co-authored-by: scb261 <65343233+scb261@users.noreply.github.com> --- src/all/hentaihand/AndroidManifest.xml | 2 + src/all/hentaihand/build.gradle | 13 + .../res/mipmap-hdpi/ic_launcher.png | Bin 0 -> 2865 bytes .../res/mipmap-mdpi/ic_launcher.png | Bin 0 -> 1654 bytes .../res/mipmap-xhdpi/ic_launcher.png | Bin 0 -> 3481 bytes .../res/mipmap-xxhdpi/ic_launcher.png | Bin 0 -> 5864 bytes .../res/mipmap-xxxhdpi/ic_launcher.png | Bin 0 -> 7566 bytes src/all/hentaihand/res/web_hi_res_512.png | Bin 0 -> 20992 bytes .../extension/all/hentaihand/HentaiHand.kt | 256 ++++++++++++++++++ .../all/hentaihand/HentaiHandFactory.kt | 15 + 10 files changed, 286 insertions(+) create mode 100644 src/all/hentaihand/AndroidManifest.xml create mode 100644 src/all/hentaihand/build.gradle create mode 100644 src/all/hentaihand/res/mipmap-hdpi/ic_launcher.png create mode 100644 src/all/hentaihand/res/mipmap-mdpi/ic_launcher.png create mode 100644 src/all/hentaihand/res/mipmap-xhdpi/ic_launcher.png create mode 100644 src/all/hentaihand/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 src/all/hentaihand/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 src/all/hentaihand/res/web_hi_res_512.png create mode 100644 src/all/hentaihand/src/eu/kanade/tachiyomi/extension/all/hentaihand/HentaiHand.kt create mode 100644 src/all/hentaihand/src/eu/kanade/tachiyomi/extension/all/hentaihand/HentaiHandFactory.kt diff --git a/src/all/hentaihand/AndroidManifest.xml b/src/all/hentaihand/AndroidManifest.xml new file mode 100644 index 000000000..30deb7f79 --- /dev/null +++ b/src/all/hentaihand/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/src/all/hentaihand/build.gradle b/src/all/hentaihand/build.gradle new file mode 100644 index 000000000..c205ecbf1 --- /dev/null +++ b/src/all/hentaihand/build.gradle @@ -0,0 +1,13 @@ +apply plugin: 'com.android.application' +apply plugin: 'kotlin-android' + +ext { + extName = 'HentaiHand' + pkgNameSuffix = 'all.hentaihand' + extClass = '.HentaiHandFactory' + extVersionCode = 1 + libVersion = '1.2' + containsNsfw = true +} + +apply from: "$rootDir/common.gradle" diff --git a/src/all/hentaihand/res/mipmap-hdpi/ic_launcher.png b/src/all/hentaihand/res/mipmap-hdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..336381de22629e5840b7a9c7178dcae10154e2d5 GIT binary patch literal 2865 zcmV-13(oY3P)QLY3$#8WR@iYV`5BC&awwY0R% z&V!9Z{*^Z8m&*#sd4`*Vrn4R|ab~|ltZFc6(o9CI<)>b>wXcW|(yg-S-(b?CYdP1CG=uIu{Qcs%}kTU%Q*A!PEXD<=>L z%t;0)mq#LzCo8R-M&eWgRIYj$W1y6Rv;(%J&KE2mb~Q*WSB)iY)w!!Y_QfvLsP8js~w7ob`#EC0&TVT5!TAq_@I zgRX0%0Ft08W+aLE;?xwV+Nv3C^|VBEJbt@^-}lRSW4DZ@oodz9vwR`LTTh61`$-Y^ z+#uE$s1`8QwDo92!_kLiWHT~O9h9-6OYw#A!jU8iYnD=+9~6*F3)r<@@Wl~DvGzc< z#&H9+gf$Gt+V~qpS zb-lk*l+i9LXY~|-BxEyE*$Q&vD2ih5HEtkL6vrQEw9Cr82!%owEU7}rTD4fg`>)8z zW+V(eBq17>M*!tA47m)$XU8aB`XNP6LPBd;g09I>6dAHC*c`qqo+>lLuGSHR2n@faTD@<5yo+~9+V9tyLZJ|LtXGjcZswo+6!a|ApzC@`7$;D?O~$p0DO5$mlB*;< zcMroyhoqv48BS4rdX(byVG$o667kVN^XJ*aW~a)g%yw>uFC@hwm*PBuES$OkS=FKI zI(DpAY@l-~1yA0oA{x<)ki2lLo4KMW=xmd*eI3J}pJ%v`V#sAA{P#76KRqjAV6%A= z-n3f4+N%YuNeWoi#bfmn9=$7hJbD|CUv1-X`XHZ&@&~ezoH#WFa_=i{pzM%>llx`d zxmxu^apUNkg71G@#@kOZd~(!UQWD;Kf#Tj91T2b)i0BlIiN0NkiUOiKhfUW9aq?Ae ze1QDgwXW;fzFt9Ys5qa#CS&*a6eQy++M_C>5f!a18d@VNVo?ngnw1mICEaA6%WDIRHb9}pm-#sDWy}b;dQ?H3xFG>Fw(zdr56tLy_$8&NT^&TUSu*-XP)+Pf?sZ<~{&g6~v&cv;eeUw1FzA zBA(~5a9$86o(&WMaU54)AiqxJ1X|lYauV(d$udJ%yNCn#iz80RM>d;X%LYn`zCeB( zwjc|mgAK+YF;&Qq`($XPw*p8Tl_#Y^{@cPbl56QL=h14yue%HcSHu3Hqq`PWRK z-Mw`LVvO~>af*S=jx?Mq1}gOi!a`z<;m2!5{AWN!HZ9`FX2ArKMZE9>0ViMOapE~1 z$&QggeveNrpk*CF{Nu&BIQdF5`qni!4#+uKS(dTww#tFrRm2#>+HQ)I`$S|@77ztv z6tRea#W5aTZ9EjYG?4oe%JV#!7(^o4j6}2<5w*@0RH_mx0rK0A7-Q(^6!G^L%^UgA zEdnC?$cO9BcUq;Y#|gx79D>0hg26%u8%H39;S?RQ2bJ2WEudtFh`;VNfl^y}wCLXN zue{>-e8<9Yr!FVyS^{~!eJB9&$UMxWB_xihlyX($bpdrl`QbDa=*FwfR_ul3#PO~m z9+{t*K;<@MuVpos)D>vc8j5$H5%JE`B33Ob0F{b$;G>ixF;B$nkMel;X%5fa#lujA zimRp;I5h+Etq6%hl_^x2+8Kl2jjkp zyC>dAoVoy&ns_OYQlArSbk)=xsNB9%35?%es*;VkUN|)Y8gH0O4yYVPDUedjs*xx) z0}=$GzY>s2U@k_Sh5^+Qrja;f0h&YznaOe7ZpPRbl|od~oh}9xD?HDC83+XSkWu_Q z)FeX4<;~5_8!4rq)&k~Y!^r~;H#IeFAcV}U7U(iU$nzV6Y%-Y;@|8<8lS$zVPA100m>3h|q96YQL^oq6Z$$d- P00000NkvXXu0mjfC@x7N literal 0 HcmV?d00001 diff --git a/src/all/hentaihand/res/mipmap-mdpi/ic_launcher.png b/src/all/hentaihand/res/mipmap-mdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..c90b88eae639f32b5a5e69674fc5ddc7ce39c884 GIT binary patch literal 1654 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 EA2McdssI20 literal 0 HcmV?d00001 diff --git a/src/all/hentaihand/res/mipmap-xxhdpi/ic_launcher.png b/src/all/hentaihand/res/mipmap-xxhdpi/ic_launcher.png new file mode 100644 index 0000000000000000000000000000000000000000..739c509e2f6e06b5f8b468259f6d1607a05b1bad GIT binary patch literal 5864 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 z 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 N`FU?^`VN*f{0Bv6n1uiU literal 0 HcmV?d00001 diff --git a/src/all/hentaihand/src/eu/kanade/tachiyomi/extension/all/hentaihand/HentaiHand.kt b/src/all/hentaihand/src/eu/kanade/tachiyomi/extension/all/hentaihand/HentaiHand.kt new file mode 100644 index 000000000..d37b36559 --- /dev/null +++ b/src/all/hentaihand/src/eu/kanade/tachiyomi/extension/all/hentaihand/HentaiHand.kt @@ -0,0 +1,256 @@ +package eu.kanade.tachiyomi.extension.all.hentaihand + +import android.annotation.SuppressLint +import com.github.salomonbrys.kotson.fromJson +import com.github.salomonbrys.kotson.get +import com.github.salomonbrys.kotson.nullObj +import com.github.salomonbrys.kotson.nullString +import com.google.gson.Gson +import com.google.gson.JsonArray +import com.google.gson.JsonObject +import eu.kanade.tachiyomi.annotations.Nsfw +import eu.kanade.tachiyomi.network.GET +import eu.kanade.tachiyomi.network.asObservableSuccess +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 okhttp3.HttpUrl +import okhttp3.OkHttpClient +import okhttp3.Request +import okhttp3.Response +import rx.Observable +import rx.schedulers.Schedulers +import java.text.SimpleDateFormat + +@Nsfw +class HentaiHand(override val lang: String, val hhLangId: Int) : HttpSource() { + + override val baseUrl: String = "https://hentaihand.com" + override val name: String = "HentaiHand" + override val supportsLatest = true + + private val gson = Gson() + + override val client: OkHttpClient = network.cloudflareClient + + private fun parseGenericResponse(response: Response): MangasPage { + val data = gson.fromJson(response.body()!!.string()) + return MangasPage( + data.getAsJsonArray("data").map { + SManga.create().apply { + url = "/en/comic/${it["slug"].asString}" + title = it["title"].asString + thumbnail_url = it["thumb_url"].asString + } + }, + !data["next_page_url"].isJsonNull + ) + } + + // Popular + + override fun popularMangaParse(response: Response): MangasPage = parseGenericResponse(response) + + override fun popularMangaRequest(page: Int): Request { + return GET("$baseUrl/api/comics?page=$page&sort=popularity&order=desc&duration=all&languages=$hhLangId") + } + + // Latest + + override fun latestUpdatesParse(response: Response): MangasPage = parseGenericResponse(response) + + override fun latestUpdatesRequest(page: Int): Request { + return GET("$baseUrl/api/comics?page=$page&sort=uploaded_at&order=desc&duration=week&languages=$hhLangId") + } + + // Search + + override fun searchMangaParse(response: Response): MangasPage = parseGenericResponse(response) + + private fun lookupFilterId(query: String, uri: String): Int? { + // filter query needs to be resolved to an ID + return client.newCall(GET("$baseUrl/api/$uri?q=$query")) + .asObservableSuccess() + .subscribeOn(Schedulers.io()) + .map { + val data = gson.fromJson(it.body()!!.string()) + // only the first tag will be used + data.getAsJsonArray("data").firstOrNull()?.let { t -> t["id"].asInt } + }.toBlocking().first() + } + + override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { + + val url = HttpUrl.parse("$baseUrl/api/comics")!!.newBuilder() + .addQueryParameter("page", page.toString()) + .addQueryParameter("q", query) + .addQueryParameter("languages", hhLangId.toString()) + + (if (filters.isEmpty()) getFilterList() else filters).forEach { filter -> + when (filter) { + is SortFilter -> url.addQueryParameter("sort", getSortPairs()[filter.state].second) + is OrderFilter -> url.addQueryParameter("order", getOrderPairs()[filter.state].second) + is DurationFilter -> url.addQueryParameter("duration", getDurationPairs()[filter.state].second) + is AttributesGroupFilter -> filter.state.forEach { + if (it.state) url.addQueryParameter("attributes", it.value) + } + is LookupFilter -> { + filter.state.split(",").map { it.trim() }.filter { it.isNotBlank() }.map { + lookupFilterId(it, filter.uri) ?: throw Exception("No ${filter.singularName} \"$it\" was found") + }.forEach { + if (!(filter.uri == "languages" && it == hhLangId)) + url.addQueryParameter(filter.uri, it.toString()) + } + } + else -> {} + } + } + + return GET(url.toString()) + } + + // Details + + private fun tagArrayToString(array: JsonArray, key: String = "name"): String? { + if (array.size() == 0) + return null + return array.joinToString { it[key].asString } + } + + private fun mangaDetailsApiRequest(manga: SManga): Request { + val slug = manga.url.removePrefix("/en/comic/") + return GET("$baseUrl/api/comics/$slug") + } + + override fun fetchMangaDetails(manga: SManga): Observable { + return client.newCall(mangaDetailsApiRequest(manga)) + .asObservableSuccess() + .map { mangaDetailsParse(it).apply { initialized = true } } + } + + override fun mangaDetailsParse(response: Response): SManga { + val data = gson.fromJson(response.body()!!.string()) + return SManga.create().apply { + + artist = tagArrayToString(data.getAsJsonArray("artists")) + author = tagArrayToString(data.getAsJsonArray("authors")) ?: artist + + genre = listOf("tags", "relationships").map { + data.getAsJsonArray(it).map { t -> t["name"].asString } + }.flatten().distinct().joinToString() + + status = SManga.COMPLETED + + description = listOf( + Pair("Alternative Title", data["alternative_title"].nullString), + Pair("Groups", tagArrayToString(data.getAsJsonArray("groups"))), + Pair("Description", data["description"].nullString), + Pair("Pages", data["pages"].asInt.toString()), + Pair("Category", data["category"].nullObj?.get("name")?.asString), + Pair("Language", data["language"].nullObj?.get("name")?.asString), + Pair("Parodies", tagArrayToString(data.getAsJsonArray("parodies"))), + Pair("Characters", tagArrayToString(data.getAsJsonArray("characters"))) + ).filter { !it.second.isNullOrEmpty() }.joinToString("\n\n") { "${it.first}:\n${it.second}" } + } + } + + // Chapters + + override fun chapterListRequest(manga: SManga): Request = mangaDetailsApiRequest(manga) + + override fun chapterListParse(response: Response): List { + val data = gson.fromJson(response.body()!!.string()) + return listOf( + SChapter.create().apply { + url = "/en/comic/${data["slug"].asString}/reader/1" + name = "Chapter" + date_upload = DATE_FORMAT.parse(data["uploaded_at"].asString)?.time ?: 0 + chapter_number = 1f + } + ) + } + + // Pages + + override fun pageListRequest(chapter: SChapter): Request { + val slug = chapter.url.removePrefix("/en/comic/").removeSuffix("/reader/1") + return GET("$baseUrl/api/comics/$slug/images") + } + + override fun pageListParse(response: Response): List { + val data = gson.fromJson(response.body()!!.string()) + return data.getAsJsonArray("images").mapIndexed { i, it -> + Page(i, "/en/comic/${data["comic"]["slug"].asString}/reader/${it["page"].asInt}", it["source_url"].asString) + } + } + + override fun imageUrlParse(response: Response): String = throw UnsupportedOperationException("Not used") + + // Filters + + private class SortFilter(sortPairs: List>) : Filter.Select("Sort By", sortPairs.map { it.first }.toTypedArray()) + private class OrderFilter(orderPairs: List>) : Filter.Select("Order By", orderPairs.map { it.first }.toTypedArray()) + private class DurationFilter(durationPairs: List>) : Filter.Select("Duration", durationPairs.map { it.first }.toTypedArray()) + private class AttributeFilter(name: String, val value: String) : Filter.CheckBox(name) + private class AttributesGroupFilter(attributePairs: List>) : Filter.Group("Attributes", attributePairs.map { AttributeFilter(it.first, it.second) }) + + private class CategoriesFilter : LookupFilter("Categories", "categories", "category") + private class TagsFilter : LookupFilter("Tags", "tags", "tag") + private class ArtistsFilter : LookupFilter("Artists", "artists", "artist") + private class GroupsFilter : LookupFilter("Groups", "groups", "group") + private class CharactersFilter : LookupFilter("Characters", "characters", "character") + private class ParodiesFilter : LookupFilter("Parodies", "parodies", "parody") + private class LanguagesFilter : LookupFilter("Other Languages", "languages", "language") + open class LookupFilter(name: String, val uri: String, val singularName: String) : Filter.Text(name) + + override fun getFilterList() = FilterList( + SortFilter(getSortPairs()), + OrderFilter(getOrderPairs()), + DurationFilter(getDurationPairs()), + Filter.Header("Separate terms with commas (,)"), + CategoriesFilter(), + TagsFilter(), + ArtistsFilter(), + GroupsFilter(), + CharactersFilter(), + ParodiesFilter(), + LanguagesFilter(), + AttributesGroupFilter(getAttributePairs()) + ) + + private fun getSortPairs() = listOf( + Pair("Upload Date", "uploaded_at"), + Pair("Title", "title"), + Pair("Pages", "pages"), + Pair("Favorites", "favorites"), + Pair("Popularity", "popularity") + ) + + private fun getOrderPairs() = listOf( + Pair("Descending", "desc"), + Pair("Ascending", "asc") + ) + + private fun getDurationPairs() = listOf( + Pair("Today", "day"), + Pair("This Week", "week"), + Pair("This Month", "month"), + Pair("This Year", "year"), + Pair("All Time", "all") + ) + + private fun getAttributePairs() = listOf( + Pair("Translated", "translated"), + Pair("Speechless", "speechless"), + Pair("Rewritten", "rewritten") + ) + + companion object { + @SuppressLint("SimpleDateFormat") + private val DATE_FORMAT = SimpleDateFormat("yyyy-dd-MM") + } +} diff --git a/src/all/hentaihand/src/eu/kanade/tachiyomi/extension/all/hentaihand/HentaiHandFactory.kt b/src/all/hentaihand/src/eu/kanade/tachiyomi/extension/all/hentaihand/HentaiHandFactory.kt new file mode 100644 index 000000000..eee5d1542 --- /dev/null +++ b/src/all/hentaihand/src/eu/kanade/tachiyomi/extension/all/hentaihand/HentaiHandFactory.kt @@ -0,0 +1,15 @@ +package eu.kanade.tachiyomi.extension.all.hentaihand + +import eu.kanade.tachiyomi.annotations.Nsfw +import eu.kanade.tachiyomi.source.Source +import eu.kanade.tachiyomi.source.SourceFactory + +@Nsfw +class HentaiHandFactory : SourceFactory { + + override fun createSources(): List = listOf( + HentaiHand("en", 1), + HentaiHand("zh", 2), + HentaiHand("ja", 3) + ) +}