YushukeMangas: Fix manga id not found (#9279)

Fix manga id not found
This commit is contained in:
Chopper 2025-06-18 10:59:58 -03:00 committed by Draff
parent 6af9f2d853
commit 67b795a5b8
Signed by: Draff
GPG Key ID: E8A89F3211677653
4 changed files with 113 additions and 15 deletions

View File

@ -129,19 +129,22 @@ abstract class YuYu(
genre = details.select(".genre-tag").joinToString { it.text() } genre = details.select(".genre-tag").joinToString { it.text() }
description = details.selectFirst(".sinopse p")?.text() description = details.selectFirst(".sinopse p")?.text()
details.selectFirst(".manga-meta > div")?.ownText()?.let { details.selectFirst(".manga-meta > div")?.ownText()?.let {
status = when (it.lowercase()) { status = it.toStatus()
"em andamento" -> SManga.ONGOING
"completo" -> SManga.COMPLETED
"cancelado" -> SManga.CANCELLED
"hiato" -> SManga.ON_HIATUS
else -> SManga.UNKNOWN
}
} }
setUrlWithoutDomain(document.location())
} }
private fun SManga.fetchMangaId(): String { protected fun String.toStatus(): Int {
val document = client.newCall(mangaDetailsRequest(this)).execute().asJsoup() return when (lowercase()) {
"em andamento" -> SManga.ONGOING
"completo" -> SManga.COMPLETED
"cancelado" -> SManga.CANCELLED
"hiato" -> SManga.ON_HIATUS
else -> SManga.UNKNOWN
}
}
protected open fun getMangaId(manga: SManga): String {
val document = client.newCall(mangaDetailsRequest(manga)).execute().asJsoup()
return document.select("script") return document.select("script")
.map(Element::data) .map(Element::data)
.firstOrNull(MANGA_ID_REGEX::containsMatchIn) .firstOrNull(MANGA_ID_REGEX::containsMatchIn)
@ -159,11 +162,11 @@ abstract class YuYu(
} }
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> { override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
val mangaId = manga.fetchMangaId() val mangaId = getMangaId(manga)
val chapters = mutableListOf<SChapter>() val chapters = mutableListOf<SChapter>()
var page = 1 var page = 1
do { do {
val dto = fetchChapterListPage(mangaId, page++).parseAs<ChaptersDto>() val dto = fetchChapterListPage(mangaId, page++).parseAs<ChaptersDto<String>>()
val document = Jsoup.parseBodyFragment(dto.chapters, baseUrl) val document = Jsoup.parseBodyFragment(dto.chapters, baseUrl)
chapters += document.select(chapterListSelector()).map(::chapterFromElement) chapters += document.select(chapterListSelector()).map(::chapterFromElement)
} while (dto.hasNext()) } while (dto.hasNext())
@ -194,7 +197,7 @@ abstract class YuYu(
// ============================== Utilities =========================== // ============================== Utilities ===========================
@Serializable @Serializable
class ChaptersDto(val chapters: String, private val remaining: Int) { class ChaptersDto<T>(val chapters: T, private val remaining: Int) {
fun hasNext() = remaining > 0 fun hasNext() = remaining > 0
} }

View File

@ -3,7 +3,7 @@ ext {
extClass = '.YushukeMangas' extClass = '.YushukeMangas'
themePkg = 'yuyu' themePkg = 'yuyu'
baseUrl = 'https://new.yushukemangas.com' baseUrl = 'https://new.yushukemangas.com'
overrideVersionCode = 6 overrideVersionCode = 7
isNsfw = false isNsfw = false
} }

View File

@ -0,0 +1,25 @@
package eu.kanade.tachiyomi.extension.pt.yushukemangas
import eu.kanade.tachiyomi.extension.pt.yushukemangas.YushukeMangas.Companion.dateFormat
import eu.kanade.tachiyomi.source.model.SChapter
import keiyoushi.utils.tryParse
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
class ChapterDto(
val id: Int,
@SerialName("numero")
val number: Float,
@SerialName("titulo")
val name: String,
@SerialName("data_publicacao")
val date: String,
) {
fun toSChapter(chapterUrl: String) = SChapter.create().apply {
name = this@ChapterDto.name
chapter_number = number
date_upload = dateFormat.tryParse(date)
url = "$chapterUrl/capitulo/$id"
}
}

View File

@ -1,7 +1,17 @@
package eu.kanade.tachiyomi.extension.pt.yushukemangas package eu.kanade.tachiyomi.extension.pt.yushukemangas
import eu.kanade.tachiyomi.multisrc.yuyu.YuYu import eu.kanade.tachiyomi.multisrc.yuyu.YuYu
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.interceptor.rateLimit import eu.kanade.tachiyomi.network.interceptor.rateLimit
import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import keiyoushi.utils.parseAs
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Response
import org.jsoup.nodes.Document
import rx.Observable
import java.text.SimpleDateFormat
import java.util.Locale
class YushukeMangas : YuYu( class YushukeMangas : YuYu(
"Yushuke Mangas", "Yushuke Mangas",
@ -10,8 +20,68 @@ class YushukeMangas : YuYu(
) { ) {
override val client = super.client.newBuilder() override val client = super.client.newBuilder()
.rateLimit(1, 2) .rateLimit(2)
.build() .build()
override val versionId = 2 override val versionId = 2
override fun mangaDetailsParse(document: Document): SManga {
if (document.location().contains(MANGA_URL_ID_REGEX).not()) {
return super.mangaDetailsParse(document)
}
return SManga.create().apply {
title = document.selectFirst("h1")!!.text()
thumbnail_url = document.selectFirst(".detalhe-capa-img")?.absUrl("src")
genre = document.select(".detalhe-tags-chips span").joinToString { it.text() }
description = document.selectFirst(".detalhe-sinopse")?.text()
document.selectFirst(".detalhe-chip.status")?.ownText()?.let {
status = it.toStatus()
}
}
}
override fun getMangaId(manga: SManga): String {
return when {
manga.isOldEntry() -> super.getMangaId(manga)
else -> MANGA_URL_ID_REGEX.find(manga.url)?.groups?.get(1)?.value ?: ""
}
}
private fun SManga.isOldEntry(): Boolean = MANGA_URL_ID_REGEX.containsMatchIn(url).not()
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
if (manga.isOldEntry()) {
return super.fetchChapterList(manga)
}
val mangaId = getMangaId(manga).takeIf(String::isNotBlank)
?: throw Exception("Manga ID não encontrado")
val chapters = mutableListOf<SChapter>()
var page = 1
val url = manga.url.replace("/$mangaId", "")
do {
val chaptersDto = fetchChapterListPage(mangaId, page++).parseAs<ChaptersDto<List<ChapterDto>>>()
chapters += chaptersDto.chapters.map { it.toSChapter(url) }
} while (chaptersDto.hasNext())
return Observable.just(chapters)
}
private fun fetchChapterListPage(mangaId: String, page: Int): Response {
val url = "$baseUrl/ajax/get_chapters.php".toHttpUrl().newBuilder()
.addQueryParameter("manga_id", mangaId)
.addQueryParameter("page", page.toString())
.build()
return client
.newCall(GET(url, headers))
.execute()
}
companion object {
val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.ROOT)
private val MANGA_URL_ID_REGEX = """\/obra\/(\d+)\/.+$""".toRegex()
}
} }