AnimeXNovel: Fix loading chapters (#9392)

Fix loading chapters
This commit is contained in:
Chopper 2025-06-23 14:09:54 -03:00 committed by Draff
parent ee6ec2bd75
commit 53ff72f22c
Signed by: Draff
GPG Key ID: E8A89F3211677653
3 changed files with 76 additions and 27 deletions

View File

@ -3,7 +3,7 @@ ext {
extClass = '.AnimeXNovel' extClass = '.AnimeXNovel'
themePkg = 'zeistmanga' themePkg = 'zeistmanga'
baseUrl = 'https://www.animexnovel.com' baseUrl = 'https://www.animexnovel.com'
overrideVersionCode = 1 overrideVersionCode = 2
isNsfw = false isNsfw = false
} }

View File

@ -1,15 +1,19 @@
package eu.kanade.tachiyomi.extension.pt.animexnovel package eu.kanade.tachiyomi.extension.pt.animexnovel
import eu.kanade.tachiyomi.multisrc.zeistmanga.ZeistManga import eu.kanade.tachiyomi.multisrc.zeistmanga.ZeistManga
import eu.kanade.tachiyomi.multisrc.zeistmanga.ZeistMangaDto
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.source.model.MangasPage import eu.kanade.tachiyomi.source.model.MangasPage
import eu.kanade.tachiyomi.source.model.SChapter import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.util.asJsoup import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.decodeFromString import keiyoushi.utils.parseAs
import keiyoushi.utils.tryParse
import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Response import okhttp3.Response
import org.jsoup.nodes.Element
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.Locale
class AnimeXNovel : ZeistManga( class AnimeXNovel : ZeistManga(
"AnimeXNovel", "AnimeXNovel",
@ -24,19 +28,13 @@ class AnimeXNovel : ZeistManga(
override val popularMangaSelectorUrl = popularMangaSelectorTitle override val popularMangaSelectorUrl = popularMangaSelectorTitle
override fun popularMangaParse(response: Response): MangasPage { override fun popularMangaParse(response: Response): MangasPage {
return super.popularMangaParse(response).let { mangaPage -> return super.popularMangaParse(response).let(::filterMangaEntries)
mangaPage.mangas.filter { it.title.contains("[Mangá]") }.let {
mangaPage.copy(it)
}
}
} }
// ============================== Latest =============================== // ============================== Latest ===============================
override fun latestUpdatesParse(response: Response): MangasPage { override fun latestUpdatesParse(response: Response): MangasPage {
return super.latestUpdatesParse(response).let { return super.latestUpdatesParse(response).let(::filterMangaEntries)
it.copy(it.mangas.filter { it.title.contains("[Mangá]") })
}
} }
// ============================== Details =============================== // ============================== Details ===============================
@ -47,7 +45,7 @@ class AnimeXNovel : ZeistManga(
thumbnail_url = document.selectFirst(".thumb")?.absUrl("src") thumbnail_url = document.selectFirst(".thumb")?.absUrl("src")
description = document.selectFirst("#synopsis")?.text() description = document.selectFirst("#synopsis")?.text()
document.selectFirst("span[data-status]")?.let { document.selectFirst("span[data-status]")?.let {
status = parseStatus(it.text()) status = parseStatus(it.text().lowercase())
} }
genre = document.select("dl:has(dt:contains(Gênero)) dd a") genre = document.select("dl:has(dt:contains(Gênero)) dd a")
.joinToString { it.text() } .joinToString { it.text() }
@ -57,31 +55,67 @@ class AnimeXNovel : ZeistManga(
// ============================== Chapters =============================== // ============================== Chapters ===============================
override val chapterCategory = "Capítulo"
override fun chapterListParse(response: Response): List<SChapter> { override fun chapterListParse(response: Response): List<SChapter> {
val document = response.asJsoup() val document = response.asJsoup()
val url = getChapterFeedUrl(document).toHttpUrl().newBuilder() val label = document.select("script")
.setQueryParameter("start-index", "1") .map(Element::data)
.firstOrNull(MANGA_TITLE_REGEX::containsMatchIn)?.let {
MANGA_TITLE_REGEX.find(it)?.groups?.get(1)?.value
} ?: return emptyList()
val chapters = mutableListOf<SChapter>() val script = document.select("script")
do { .map(Element::data)
val res = client.newCall(GET(url.build(), headers)).execute() .firstOrNull(API_KEY_REGEX::containsMatchIn)
?: return emptyList()
val page = json.decodeFromString<ZeistMangaDto>(res.body.string()).feed?.entry val blogId = BLOG_ID_REGEX.find(script)?.groups?.get(1)?.value ?: return emptyList()
?.filter { it.category.orEmpty().any { category -> category.term == chapterCategory } } val apiKey = API_KEY_REGEX.find(script)?.groups?.get(1)?.value ?: return emptyList()
?.map { it.toSChapter(baseUrl) }
?: emptyList()
chapters += page val url = "https://www.googleapis.com/blogger/v3/blogs/$blogId/posts".toHttpUrl().newBuilder()
url.setQueryParameter("start-index", "${chapters.size + 1}") .addQueryParameter("key", apiKey)
} while (page.isNotEmpty()) .addQueryParameter("labels", label)
.addQueryParameter("maxResults", "500")
.build()
return chapters val response = client.newCall(GET(url, headers)).execute()
if (response.isSuccessful.not()) {
throw IOException("Capítulos não encontrados")
}
return response.parseAs<ChapterWrapperDto>().items.map {
SChapter.create().apply {
name = it.title
date_upload = dateFormat.tryParse(it.published)
setUrlWithoutDomain(it.url)
}
}
} }
// ============================== Pages =============================== // ============================== Pages ===============================
override val pageListSelector = "#reader .separator" override val pageListSelector = "#reader .separator"
// ============================== Utils ===============================
private fun filterMangaEntries(mangasPage: MangasPage): MangasPage {
val prefix = "[Mangá]"
return mangasPage.copy(
mangasPage.mangas.filter {
it.title.contains(prefix)
}.map {
it.apply {
title = title.substringAfter(prefix).trim()
}
},
)
}
companion object {
private val API_KEY_REGEX = """(?:API_KEY(?:\s+)?=(?:\s+)?.)"([^(\\|")]+)""".toRegex()
private val BLOG_ID_REGEX = """(?:BLOG_ID(?:\s+)?=(?:\s+)?.)"([^(\\|")]+)""".toRegex()
private val MANGA_TITLE_REGEX = """iniciarCapituloLoader\("([^"]+)"\)""".toRegex()
private val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.ROOT)
}
} }

View File

@ -0,0 +1,15 @@
package eu.kanade.tachiyomi.extension.pt.animexnovel
import kotlinx.serialization.Serializable
@Serializable
class ChapterWrapperDto(
val items: List<ChapterDto>,
)
@Serializable
class ChapterDto(
val title: String,
val published: String,
val url: String,
)