* Add Akaya

* add formbody in interceptor

* Minor change
This commit is contained in:
bapeey 2024-05-08 11:17:21 -05:00 committed by GitHub
parent f36ad9071b
commit 55e01146e4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 276 additions and 0 deletions

View File

@ -0,0 +1,8 @@
ext {
extName = 'AKAYA'
extClass = '.Akaya'
extVersionCode = 1
isNsfw = true
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

View File

@ -0,0 +1,220 @@
package eu.kanade.tachiyomi.extension.es.akaya
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.asObservableSuccess
import eu.kanade.tachiyomi.network.interceptor.rateLimitHost
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.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.FormBody
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import rx.Observable
import java.io.IOException
import java.text.ParseException
import java.text.SimpleDateFormat
import java.util.Locale
class Akaya : ParsedHttpSource() {
override val name: String = "AKAYA"
override val baseUrl: String = "https://akaya.io"
override val lang: String = "es"
override val supportsLatest: Boolean = true
override val client = network.cloudflareClient.newBuilder()
.rateLimitHost(baseUrl.toHttpUrl(), 1, 1)
.addInterceptor { chain ->
val request = chain.request()
if (!request.url.toString().startsWith("$baseUrl/serie")) return@addInterceptor chain.proceed(request)
val response = chain.proceed(request)
if (response.request.url.toString().removeSuffix("/") == baseUrl) {
throw IOException("Esta serie no se encuentra disponible")
}
return@addInterceptor response
}
.addInterceptor { chain ->
val request = chain.request()
if (!request.url.toString().startsWith("$baseUrl/search")) return@addInterceptor chain.proceed(request)
val query = request.url.fragment!!
if (csrfToken.isEmpty()) getCsrftoken()
val response = chain.proceed(addFormBody(request, query))
if (response.code == 419) {
response.close()
getCsrftoken()
return@addInterceptor chain.proceed(addFormBody(request, query))
}
return@addInterceptor response
}
.build()
private fun addFormBody(request: Request, query: String): Request {
val body = FormBody.Builder()
.add("_token", csrfToken)
.add("search", query)
.build()
return request.newBuilder()
.url(request.url.toString().substringBefore("#"))
.post(body)
.build()
}
override fun headersBuilder() = super.headersBuilder()
.set("Referer", "$baseUrl/")
override fun popularMangaRequest(page: Int): Request =
GET("$baseUrl/collection/bd90cb43-9bf2-4759-b8cc-c9e66a526bc6?page=$page", headers)
override fun popularMangaSelector() = searchMangaSelector()
override fun popularMangaNextPageSelector() = searchMangaNextPageSelector()
override fun popularMangaFromElement(element: Element) = searchMangaFromElement(element)
override fun latestUpdatesRequest(page: Int): Request =
GET("$baseUrl/collection/0031a504-706c-4666-9782-a4ae30cad973?page=$page", headers)
override fun latestUpdatesSelector() = popularMangaSelector()
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
override fun latestUpdatesFromElement(element: Element) = popularMangaFromElement(element)
private var csrfToken: String = ""
override fun fetchSearchManga(page: Int, query: String, filters: FilterList): Observable<MangasPage> {
if (query.isEmpty()) return super.fetchSearchManga(page, query, filters)
return client.newCall(querySearchMangaRequest(query)).asObservableSuccess().map { response ->
querySearchMangaParse(response)
}
}
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val url = baseUrl.toHttpUrl().newBuilder()
val order = filters.filterIsInstance<OrderFilter>().first().toUriPart()
val genres = filters.filterIsInstance<GenreFilter>().first().state
.filter(Genre::state)
.map(Genre::id)
url.addPathSegment(order)
if (genres.isNotEmpty()) url.addPathSegment(genres.joinToString(",", "[", "]"))
url.addQueryParameter("page", page.toString())
return GET(url.build(), headers)
}
private fun getCsrftoken() {
val response = client.newCall(GET(baseUrl, headers)).execute()
val document = response.asJsoup()
csrfToken = document.selectFirst("meta[name=csrf-token]")!!.attr("content")
}
private fun querySearchMangaRequest(query: String): Request = POST("$baseUrl/search#$query", headers)
private fun querySearchMangaParse(response: Response): MangasPage {
val document = response.asJsoup()
val mangas = document.select("main > div.search-title > div.rowDiv div.list-search:has(div.inner-img-search)").map {
SManga.create().apply {
setUrlWithoutDomain(it.selectFirst("div.name-serie-search > a")!!.attr("href"))
thumbnail_url = it.selectFirst("div.inner-img-search")!!.attr("style")
.substringAfter("url(").substringBefore(")")
title = it.select("div.name-serie-search").text()
}
}
return MangasPage(mangas, false)
}
override fun getFilterList() = FilterList(
Filter.Header("Los filtros se ignorarán al hacer una búsqueda por texto"),
Filter.Separator(),
OrderFilter(),
GenreFilter(),
)
override fun searchMangaSelector() = "div.serie_items > div.library-grid-item"
override fun searchMangaNextPageSelector() = "div.wrapper-navigation ul.pagination > li > a[rel=next]"
override fun searchMangaFromElement(element: Element) = SManga.create().apply {
setUrlWithoutDomain(element.selectFirst("a")!!.attr("href"))
title = element.selectFirst("span > h5 > strong")!!.text()
thumbnail_url = element.selectFirst("div.inner-img")?.attr("style")
?.substringAfter("url(")?.substringBefore(")")
?: element.selectFirst("div.img-fluid")?.attr("abs:src")
}
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
with(document.selectFirst("header.masthead > div.container > div.row")!!) {
title = selectFirst(".serie-head-title")!!.text()
author = selectFirst("ul.persons")!!.let { element ->
element.select("li").joinToString { it.text() }
.ifEmpty { element.text() }
}
genre = selectFirst("ul.categories")!!.let { element ->
element.select("li").joinToString { it.text() }
.ifEmpty { element.text() }
}
}
thumbnail_url = document.selectFirst("meta[property=og:image]")!!.attr("content")
.replace("/chapters/", "/content/")
description = document.selectFirst("section.main div.container div.sidebar > p")!!.text()
}
override fun chapterListRequest(manga: SManga): Request =
GET(baseUrl + manga.url + "?order_direction=desc", headers)
override fun chapterListSelector() = "div.chapter-desktop div.chapter-item"
override fun chapterFromElement(element: Element) = SChapter.create().apply {
setUrlWithoutDomain(element.selectFirst("div.text-left > .mt-1 > a")!!.attr("href"))
name = element.selectFirst("div.text-left > .mt-1 > a")!!.text()
date_upload = parseDate(element.selectFirst("p.date")!!.text())
element.selectFirst("i.ak-lock")?.let {
name = "🔒 $name"
url = "$url#lock"
}
}
private val dateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale("es"))
private fun parseDate(date: String): Long {
return try {
dateFormat.parse(date)?.time ?: 0L
} catch (e: ParseException) {
0L
}
}
override fun pageListRequest(chapter: SChapter): Request {
if (chapter.url.substringAfterLast("#") == "lock") {
throw Exception("Capítulo bloqueado")
}
return super.pageListRequest(chapter)
}
override fun pageListParse(document: Document): List<Page> {
return document.select("main.separatorReading div.container img.img-fluid").mapIndexed { i, img ->
Page(i, imageUrl = img.attr("abs:src"))
}
}
override fun imageUrlParse(document: Document) = throw UnsupportedOperationException()
}

View File

@ -0,0 +1,48 @@
package eu.kanade.tachiyomi.extension.es.akaya
import eu.kanade.tachiyomi.source.model.Filter
class Genre(name: String, val id: Int) : Filter.CheckBox(name)
open class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Géneros", genres)
class GenreFilter : GenreList(
listOf(
Genre("Acción", 9),
Genre("Arte", 34),
Genre("Boylove (yaoi)", 18),
Genre("Comedia", 21),
Genre("Crimen", 25),
Genre("Distópico", 15),
Genre("Drama", 35),
Genre("Fantasía", 8),
Genre("Girllove (yuri)", 27),
Genre("Isekai", 19),
Genre("LGBT", 16),
Genre("Monstruos", 10),
Genre("NSFW", 17),
Genre("Psicológico", 26),
Genre("Romance", 24),
Genre("Sci Fi", 23),
Genre("Slice of life", 13),
Genre("Steampunk", 20),
Genre("Superhéroe", 11),
Genre("Supernatural", 22),
Genre("Suspenso", 14),
Genre("Thriller", 12),
),
)
class OrderFilter() : UriPartFilter(
"Ordenar por",
arrayOf(
Pair("Populares", "genres"),
Pair("Recientes", "genres-bydate"),
Pair("Nombre", "genres-byname"),
),
)
open class UriPartFilter(displayName: String, private val vals: Array<Pair<String, String>>) :
Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
fun toUriPart() = vals[state].second
}