AllHentai: fix image loading (#5868)

This commit is contained in:
Maxim Molochkov 2024-11-04 17:21:36 +04:00 committed by GitHub
parent 613c8bcfa7
commit 4c557e29bf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 97 additions and 37 deletions

View File

@ -2,4 +2,4 @@ plugins {
id("lib-multisrc") id("lib-multisrc")
} }
baseVersionCode = 24 baseVersionCode = 25

View File

@ -65,7 +65,8 @@ abstract class GroupLe(
} }
.build() .build()
private var uagent: String = preferences.getString(UAGENT_TITLE, UAGENT_DEFAULT)!! private var uagent = preferences.getString(UAGENT_TITLE, UAGENT_DEFAULT)!!
override fun headersBuilder() = Headers.Builder().apply { override fun headersBuilder() = Headers.Builder().apply {
add("User-Agent", uagent) add("User-Agent", uagent)
add("Referer", baseUrl) add("Referer", baseUrl)
@ -206,28 +207,44 @@ abstract class GroupLe(
} }
} }
protected open fun getChapterSearchParams(document: Document): String {
return "?mtr=true"
}
private fun chapterListParse(response: Response, manga: SManga): List<SChapter> { private fun chapterListParse(response: Response, manga: SManga): List<SChapter> {
val document = response.asJsoup() val document = response.asJsoup()
if ((document.select(".expandable.hide-dn").isNotEmpty() && document.select(".user-avatar").isNullOrEmpty() && document.toString().contains("current_user_country_code = 'RU'")) || (document.select("img.logo").first()?.attr("title")?.contains("Allhentai") == true && document.select(".user-avatar").isNullOrEmpty())) { if ((
document.select(".expandable.hide-dn").isNotEmpty() && document.select(".user-avatar")
.isEmpty() && document.toString()
.contains("current_user_country_code = 'RU'")
) || (
document.select("img.logo")
.first()?.attr("title")
?.contains("Allhentai") == true && document.select(".user-avatar").isEmpty()
)
) {
throw Exception("Для просмотра контента необходима авторизация через WebView\uD83C\uDF0E") throw Exception("Для просмотра контента необходима авторизация через WebView\uD83C\uDF0E")
} }
return document.select(chapterListSelector()).map { chapterFromElement(it, manga) }
val chapterSearchParams = getChapterSearchParams(document)
return document.select(chapterListSelector()).map { chapterFromElement(it, manga, chapterSearchParams) }
} }
override fun chapterListSelector() = override fun chapterListSelector() =
"tr.item-row:has(td > a):has(td.date:not(.text-info))" "tr.item-row:has(td > a):has(td.date:not(.text-info))"
private fun chapterFromElement(element: Element, manga: SManga): SChapter { private fun chapterFromElement(element: Element, manga: SManga, chapterSearchParams: String): SChapter {
val urlElement = element.select("a.chapter-link").first()!! val urlElement = element.select("a.chapter-link").first()!!
val chapterInf = element.select("td.item-title").first()!! val chapterInf = element.select("td.item-title").first()!!
val urlText = urlElement.text() val urlText = urlElement.text()
val chapter = SChapter.create() val chapter = SChapter.create()
chapter.setUrlWithoutDomain(urlElement.attr("href") + "?mtr=true") // mtr is 18+ fractional skip chapter.setUrlWithoutDomain(urlElement.attr("href") + chapterSearchParams)
val translatorElement = urlElement.attr("title") val translatorElement = urlElement.attr("title")
chapter.scanlator = if (!translatorElement.isNullOrBlank()) { chapter.scanlator = if (translatorElement.isNotBlank()) {
translatorElement translatorElement
.replace("(Переводчик),", "&") .replace("(Переводчик),", "&")
.removeSuffix(" (Переводчик)") .removeSuffix(" (Переводчик)")
@ -292,15 +309,15 @@ abstract class GroupLe(
val html = document.html() val html = document.html()
var readerMark = "rm_h.readerDoInit([" val readerMark = "rm_h.readerDoInit(["
// allhentai necessary
if (!html.contains(readerMark)) {
readerMark = "rm_h.readerInit( 0,["
}
if (!html.contains(readerMark)) { if (!html.contains(readerMark)) {
if (document.select(".input-lg").isNotEmpty() || (document.select(".user-avatar").isNullOrEmpty() && document.select("img.logo").first()?.attr("title")?.contains("Allhentai") == true)) { if (document.select(".input-lg").isNotEmpty() || (
document.select(".user-avatar")
.isEmpty() && document.select("img.logo").first()?.attr("title")
?.contains("Allhentai") == true
)
) {
throw Exception("Для просмотра контента необходима авторизация через WebView\uD83C\uDF0E") throw Exception("Для просмотра контента необходима авторизация через WebView\uD83C\uDF0E")
} }
if (!response.request.url.toString().contains(baseUrl)) { if (!response.request.url.toString().contains(baseUrl)) {

View File

@ -3,7 +3,7 @@ ext {
extClass = '.AllHentai' extClass = '.AllHentai'
themePkg = 'grouple' themePkg = 'grouple'
baseUrl = 'https://z.ahen.me' baseUrl = 'https://z.ahen.me'
overrideVersionCode = 23 overrideVersionCode = 24
isNsfw = true isNsfw = true
} }

View File

@ -8,18 +8,27 @@ import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.source.model.Filter import eu.kanade.tachiyomi.source.model.Filter
import eu.kanade.tachiyomi.source.model.FilterList import eu.kanade.tachiyomi.source.model.FilterList
import okhttp3.Request import okhttp3.Request
import org.jsoup.nodes.Document
import uy.kohesive.injekt.Injekt import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get import uy.kohesive.injekt.api.get
class AllHentai : GroupLe("AllHentai", "https://z.ahen.me", "ru") { class AllHentai : GroupLe("AllHentai", "https://z.ahen.me", "ru") {
override val id = 1809051393403180443
override val id: Long = 1809051393403180443 private val preferences = Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
private val preferences =
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
override val baseUrl by lazy { getPrefBaseUrl() } override val baseUrl by lazy { getPrefBaseUrl() }
override fun getChapterSearchParams(document: Document): String {
val html = document.html()
val userHashRegex = "user_hash.+'(.+)'".toRegex()
val userHash = userHashRegex.find(html)?.groupValues?.get(1)
return userHash?.let { "?d=$it" } ?: ""
}
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request { override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val url = super.searchMangaRequest(page, query, filters).url.newBuilder() val url = super.searchMangaRequest(page, query, filters).url.newBuilder()
(if (filters.isEmpty()) getFilterList() else filters).forEach { filter -> (if (filters.isEmpty()) getFilterList() else filters).forEach { filter ->
@ -29,28 +38,47 @@ class AllHentai : GroupLe("AllHentai", "https://z.ahen.me", "ru") {
url.addQueryParameter(genre.id, arrayOf("=", "=in", "=ex")[genre.state]) url.addQueryParameter(genre.id, arrayOf("=", "=in", "=ex")[genre.state])
} }
} }
is Category -> filter.state.forEach { category -> is Category -> filter.state.forEach { category ->
if (category.state != Filter.TriState.STATE_IGNORE) { if (category.state != Filter.TriState.STATE_IGNORE) {
url.addQueryParameter(category.id, arrayOf("=", "=in", "=ex")[category.state]) url.addQueryParameter(
category.id,
arrayOf("=", "=in", "=ex")[category.state],
)
} }
} }
is FilList -> filter.state.forEach { fils ->
if (fils.state != Filter.TriState.STATE_IGNORE) { is FiltersList -> filter.state.forEach { filters ->
url.addQueryParameter(fils.id, arrayOf("=", "=in", "=ex")[fils.state]) if (filters.state != Filter.TriState.STATE_IGNORE) {
url.addQueryParameter(filters.id, arrayOf("=", "=in", "=ex")[filters.state])
} }
} }
is OrderBy -> { is OrderBy -> {
if (filter.state > 0) { if (filter.state > 0) {
val ord = arrayOf("not", "year", "rate", "popularity", "votes", "created", "updated")[filter.state] val sortType = arrayOf(
return GET("$baseUrl/list?sortType=$ord&offset=${70 * (page - 1)}", headers) "not",
"year",
"rate",
"popularity",
"votes",
"created",
"updated",
)[filter.state]
return GET(
"$baseUrl/list?sortType=$sortType&offset=${70 * (page - 1)}",
headers,
)
} }
} }
is Tags -> { is Tags -> {
if (filter.state > 0) { if (filter.state > 0) {
val tagName = getTagsList()[filter.state].url val tagName = tagsList[filter.state].url
return GET("$baseUrl/list/tag/$tagName?offset=${70 * (page - 1)}", headers) return GET("$baseUrl/list/tag/$tagName?offset=${70 * (page - 1)}", headers)
} }
} }
else -> {} else -> {}
} }
} }
@ -63,14 +91,25 @@ class AllHentai : GroupLe("AllHentai", "https://z.ahen.me", "ru") {
private class OrderBy : Filter.Select<String>( private class OrderBy : Filter.Select<String>(
"Сортировка (только)", "Сортировка (только)",
arrayOf("Без сортировки", "По году", "По популярности", "Популярно сейчас", "По рейтингу", "Новинки", "По дате обновления"), arrayOf(
"Без сортировки",
"По году",
"По популярности",
"Популярно сейчас",
"По рейтингу",
"Новинки",
"По дате обновления",
),
) )
private class Genre(name: String, val id: String) : Filter.TriState(name) private class Genre(name: String, val id: String) : Filter.TriState(name)
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Жанры", genres) private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Жанры", genres)
private class Category(categories: List<Genre>) : Filter.Group<Genre>("Категории", categories) private class Category(categories: List<Genre>) : Filter.Group<Genre>("Категории", categories)
private class FilList(fils: List<Genre>) : Filter.Group<Genre>("Фильтры", fils)
private class FiltersList(filters: List<Genre>) : Filter.Group<Genre>("Фильтры", filters)
private class Tags(tags: Array<String>) : Filter.Select<String>("Тэг (только)", tags) private class Tags(tags: Array<String>) : Filter.Select<String>("Тэг (только)", tags)
private data class Tag(val name: String, val url: String) private data class Tag(val name: String, val url: String)
@ -78,12 +117,12 @@ class AllHentai : GroupLe("AllHentai", "https://z.ahen.me", "ru") {
override fun getFilterList() = FilterList( override fun getFilterList() = FilterList(
OrderBy(), OrderBy(),
Tags(tagsName), Tags(tagsName),
GenreList(getGenreList()), GenreList(genreList),
Category(getCategoryList()), Category(categoryList),
FilList(getFilList()), FiltersList(filtersList),
) )
private fun getGenreList() = listOf( private val genreList = listOf(
Genre("ahegao", "el_855"), Genre("ahegao", "el_855"),
Genre("анал", "el_828"), Genre("анал", "el_828"),
Genre("бдсм", "el_78"), Genre("бдсм", "el_78"),
@ -120,7 +159,7 @@ class AllHentai : GroupLe("AllHentai", "https://z.ahen.me", "ru") {
Genre("яой", "el_83"), Genre("яой", "el_83"),
) )
private fun getCategoryList() = listOf( private val categoryList = listOf(
Genre("3D", "el_626"), Genre("3D", "el_626"),
Genre("Анимация", "el_5777"), Genre("Анимация", "el_5777"),
Genre("Без текста", "el_3157"), Genre("Без текста", "el_3157"),
@ -128,7 +167,7 @@ class AllHentai : GroupLe("AllHentai", "https://z.ahen.me", "ru") {
Genre("Порно манхва", "el_1104"), Genre("Порно манхва", "el_1104"),
) )
private fun getFilList() = listOf( private val filtersList = listOf(
Genre("Высокий рейтинг", "s_high_rate"), Genre("Высокий рейтинг", "s_high_rate"),
Genre("Сингл", "s_single"), Genre("Сингл", "s_single"),
Genre("Для взрослых", "s_mature"), Genre("Для взрослых", "s_mature"),
@ -139,7 +178,7 @@ class AllHentai : GroupLe("AllHentai", "https://z.ahen.me", "ru") {
Genre("Продается", "s_sale"), Genre("Продается", "s_sale"),
) )
private fun getTagsList() = listOf( private val tagsList = listOf(
Tag("Без тега", "not"), Tag("Без тега", "not"),
Tag("handjob", "handjob"), Tag("handjob", "handjob"),
Tag("inseki", "inseki"), Tag("inseki", "inseki"),
@ -259,7 +298,7 @@ class AllHentai : GroupLe("AllHentai", "https://z.ahen.me", "ru") {
Tag("яндере", "yandere"), Tag("яндере", "yandere"),
) )
private val tagsName = getTagsList().map { private val tagsName = tagsList.map {
it.name it.name
}.toTypedArray() }.toTypedArray()
@ -272,7 +311,11 @@ class AllHentai : GroupLe("AllHentai", "https://z.ahen.me", "ru") {
dialogTitle = DOMAIN_TITLE dialogTitle = DOMAIN_TITLE
dialogMessage = "Default URL:\n\t${super.baseUrl}" dialogMessage = "Default URL:\n\t${super.baseUrl}"
setOnPreferenceChangeListener { _, _ -> setOnPreferenceChangeListener { _, _ ->
Toast.makeText(screen.context, "Для смены домена необходимо перезапустить приложение с полной остановкой.", Toast.LENGTH_LONG).show() Toast.makeText(
screen.context,
"Для смены домена необходимо перезапустить приложение с полной остановкой.",
Toast.LENGTH_LONG,
).show()
true true
} }
}.let(screen::addPreference) }.let(screen::addPreference)