ArgosScan: Fixes (#9135)

* Fix

* Use relative manga url
This commit is contained in:
Chopper 2025-06-08 23:12:42 -03:00 committed by Draff
parent d73a90d970
commit 026666bc38
Signed by: Draff
GPG Key ID: E8A89F3211677653
4 changed files with 68 additions and 272 deletions

View File

@ -1,7 +1,7 @@
ext { ext {
extName = 'Argos Scan' extName = 'Argos Scan'
extClass = '.ArgosScan' extClass = '.ArgosScan'
extVersionCode = 24 extVersionCode = 25
} }
apply from: "$rootDir/common.gradle" apply from: "$rootDir/common.gradle"

View File

@ -2,10 +2,14 @@ package eu.kanade.tachiyomi.extension.pt.argosscan
import eu.kanade.tachiyomi.network.GET import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.source.model.FilterList 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.Page
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.source.online.ParsedHttpSource import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import keiyoushi.utils.parseAs
import keiyoushi.utils.tryParse
import okhttp3.HttpUrl.Companion.toHttpUrl import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
@ -29,7 +33,7 @@ class ArgosScan : ParsedHttpSource() {
override val client: OkHttpClient = network.cloudflareClient.newBuilder() override val client: OkHttpClient = network.cloudflareClient.newBuilder()
.addInterceptor { chain -> .addInterceptor { chain ->
val response = chain.proceed(chain.request()) val response = chain.proceed(chain.request())
if (response.request.url.pathSegments.any { it.equals("pagina-de-login", true) }) { if (response.request.url.pathSegments.any { it.equals("login", true) }) {
throw IOException("Faça login na WebView") throw IOException("Faça login na WebView")
} }
@ -43,18 +47,22 @@ class ArgosScan : ParsedHttpSource() {
// ============================ Popular ====================================== // ============================ Popular ======================================
override fun popularMangaRequest(page: Int) = GET(baseUrl, headers) override fun popularMangaRequest(page: Int) = GET(baseUrl, headers)
override fun popularMangaSelector() = ".card__main._grid:not(:has(a[href*=novel]))" override fun popularMangaSelector() = throw UnsupportedOperationException()
override fun popularMangaFromElement(element: Element) = throw UnsupportedOperationException()
override fun popularMangaFromElement(element: Element) = SManga.create().apply {
with(element.selectFirst("h3.card__title")!!) {
title = text()
setUrlWithoutDomain(selectFirst("a")!!.absUrl("href"))
}
thumbnail_url = element.selectFirst("img")?.absUrl("src")
}
override fun popularMangaNextPageSelector() = null override fun popularMangaNextPageSelector() = null
override fun popularMangaParse(response: Response): MangasPage {
val script = response.asJsoup().selectFirst("script:containsData(projects)")!!.data()
val mangas = POPULAR_REGEX.find(script)?.groups?.get(1)?.value?.let {
it.parseAs<List<MangaDto>>()
.filter { it.type != "novel" }
.map { it.toSManga(baseUrl) }
} ?: throw IOException("Não foi possivel encontrar os mangás")
return MangasPage(mangas, false)
}
// ============================ Latest ====================================== // ============================ Latest ======================================
override fun latestUpdatesRequest(page: Int) = throw UnsupportedOperationException() override fun latestUpdatesRequest(page: Int) = throw UnsupportedOperationException()
@ -83,40 +91,34 @@ class ArgosScan : ParsedHttpSource() {
// ============================ Details ===================================== // ============================ Details =====================================
override fun mangaDetailsParse(document: Document) = SManga.create().apply { override fun mangaDetailsParse(document: Document) = SManga.create().apply {
title = document.selectFirst("h1")!!.text() with(document) {
thumbnail_url = document.selectFirst("img.story__thumbnail-image")?.absUrl("src") title = selectFirst(".content h2")!!.text()
description = document.selectFirst(".story__summary p")?.text() thumbnail_url = selectFirst(".trailer-box img")?.absUrl("src")
document.selectFirst(".story__status")?.let { description = selectFirst(".content p")?.text()
status = when (it.text().trim().lowercase()) { selectFirst("section[data-status]")?.attr("data-status")?.let {
"em andamento" -> SManga.ONGOING status = it.toStatus()
else -> SManga.UNKNOWN
} }
genre = select("h6:contains(Tags) + h6 > span").joinToString { it.text() }
} }
setUrlWithoutDomain(document.location()) setUrlWithoutDomain(document.location())
} }
// ============================ Chapter ===================================== // ============================ Chapter =====================================
override fun chapterListSelector() = ".chapter-group__list li:has(a)" override fun chapterListSelector() = ".manga-chapter"
override fun chapterFromElement(element: Element) = SChapter.create().apply { override fun chapterFromElement(element: Element) = SChapter.create().apply {
with(element.selectFirst("a")!!) { name = element.selectFirst("h5")!!.text()
name = text() element.selectFirst("h6")?.let {
setUrlWithoutDomain(absUrl("href")) date_upload = dateFormat.tryParse(it.text())
} }
element.selectFirst(".chapter-group__list-item-date")?.attr("datetime")?.let { setUrlWithoutDomain(element.selectFirst("a")!!.absUrl("href"))
date_upload = it.parseDate()
}
}
override fun chapterListParse(response: Response): List<SChapter> {
return super.chapterListParse(response).sortedByDescending(SChapter::chapter_number)
} }
// ============================ Pages ======================================= // ============================ Pages =======================================
override fun pageListParse(document: Document): List<Page> { override fun pageListParse(document: Document): List<Page> {
return document.select("#chapter-content img").mapIndexed { index, element -> return document.select(".manga-page img").mapIndexed { index, element ->
Page(index, imageUrl = element.absUrl("src")) Page(index, imageUrl = element.absUrl("src"))
} }
} }
@ -125,10 +127,8 @@ class ArgosScan : ParsedHttpSource() {
// ============================== Utilities ================================== // ============================== Utilities ==================================
private fun String.parseDate(): Long {
return try { dateFormat.parse(this.trim())!!.time } catch (_: Exception) { 0L }
}
companion object { companion object {
val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.ROOT) val dateFormat = SimpleDateFormat("dd/MM/yyyy", Locale.ROOT)
val POPULAR_REGEX = """projects\s?=\s+([^;]+)""".toRegex()
} }
} }

View File

@ -1,47 +1,42 @@
package eu.kanade.tachiyomi.extension.pt.argosscan package eu.kanade.tachiyomi.extension.pt.argosscan
import eu.kanade.tachiyomi.source.model.SManga
import kotlinx.serialization.SerialName import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
@Serializable @Serializable
data class ArgosResponseDto<T>( class MangaDto(
val data: Map<String, T>? = null, @SerialName("attributes")
) val details: DetailsDto,
@SerialName("cover_image_url")
val thumbnailUrl: String,
val id: String,
val type: String,
) {
fun toSManga(baseUrl: String) = SManga.create().apply {
title = details.title.values.first()
description = details.description.values.first()
genre = details.genres.joinToString()
thumbnail_url = "$baseUrl/$thumbnailUrl"
status = details.status.toStatus()
url = "/projetos/${this@MangaDto.id}"
initialized = true
}
}
fun String.toStatus(): Int =
when (lowercase()) {
"em-lancamento" -> SManga.ONGOING
"completa" -> SManga.COMPLETED
"em-pausa" -> SManga.ON_HIATUS
else -> SManga.UNKNOWN
}
@Serializable @Serializable
data class ArgosProjectListDto( class DetailsDto(
val count: Int = 0, val title: Map<String, String>,
val currentPage: Int = 0, val description: Map<String, String> = emptyMap(),
val limit: Int = 0, val status: String,
val projects: List<ArgosProjectDto> = emptyList(), @SerialName("tags")
val totalPages: Int = 0, val genres: List<String> = emptyList(),
)
@Serializable
data class ArgosProjectDto(
val adult: Boolean? = false,
val alternative: List<String>? = emptyList(),
val authors: List<String>? = emptyList(),
val cover: String? = "",
@SerialName("getChapters") val chapters: List<ArgosChapterDto> = emptyList(),
val description: String? = "",
val id: Int = 0,
val name: String? = "",
@SerialName("getTags") val tags: List<ArgosTagDto>? = emptyList(),
val type: String? = "",
)
@Serializable
data class ArgosChapterDto(
val createAt: String? = "",
val id: String = "",
val images: List<String>? = emptyList(),
val number: Int? = 0,
val project: ArgosProjectDto? = null,
val title: String? = "",
)
@Serializable
data class ArgosTagDto(
val name: String,
) )

View File

@ -1,199 +0,0 @@
package eu.kanade.tachiyomi.extension.pt.argosscan
import kotlinx.serialization.json.add
import kotlinx.serialization.json.addJsonObject
import kotlinx.serialization.json.buildJsonObject
import kotlinx.serialization.json.put
import kotlinx.serialization.json.putJsonArray
import kotlinx.serialization.json.putJsonObject
private fun buildQuery(queryAction: () -> String) = queryAction().replace("%", "$")
val LOGIN_MUTATION_QUERY = buildQuery {
"""
| mutation login(%email: String!, %password: String!) {
| login(loginInput: { email: %email, password: %password }) {
| token
| }
| }
""".trimMargin()
}
fun buildLoginMutationQueryPayload(email: String, password: String) = buildJsonObject {
put("operationName", "login")
put("query", LOGIN_MUTATION_QUERY)
putJsonObject("variables") {
put("email", email)
put("password", password)
}
}
val POPULAR_QUERY = buildQuery {
"""
| query getProjects(
| %filters: FiltersExpression!,
| %orders: OrdersExpression!,
| %pagination: PaginationInput
| ) {
| getProjects(
| orders: %orders,
| filters: %filters,
| pagination: %pagination
| ) {
| projects {
| id
| name
| cover
| type
| updateAt
| getChapters(order: { id: DESC }, skip: 0, take: 1) {
| id
| title
| number
| }
| }
| count
| currentPage
| limit
| totalPages
| }
| }
""".trimMargin()
}
fun buildPopularQueryPayload(page: Int) = buildJsonObject {
put("operationName", "getProjects")
put("query", POPULAR_QUERY)
putJsonObject("variables") {
putJsonObject("filters") {
putJsonObject("childExpressions") {
putJsonObject("filters") {
put("field", "Project.id")
put("op", "GE")
putJsonArray("values") {
add("1")
}
}
put("operator", "AND")
}
put("operator", "AND")
}
putJsonObject("orders") {
putJsonArray("orders") {
addJsonObject {
put("field", "Project.views")
put("or", "DESC")
}
}
}
putJsonObject("pagination") {
put("limit", 12)
put("page", page)
}
}
}
fun buildSearchQueryPayload(query: String, page: Int) = buildJsonObject {
put("operationName", "getProjects")
put("query", POPULAR_QUERY)
putJsonObject("variables") {
putJsonObject("filters") {
putJsonArray("filters") {
addJsonObject {
put("field", "Project.name")
put("op", "LIKE")
putJsonArray("values") {
add(query)
}
}
}
put("operator", "AND")
}
putJsonObject("orders") {
putJsonArray("orders") {
addJsonObject {
put("field", "Project.views")
put("or", "DESC")
}
}
}
putJsonObject("pagination") {
put("limit", 10)
put("page", page)
}
}
}
val MANGA_DETAILS_QUERY = buildQuery {
"""
| query project(%id: Int!) {
| project(id: %id) {
| id
| name
| type
| description
| authors
| cover
| getChapters(order: { number: DESC }) {
| id
| number
| title
| createAt
| }
| getTags(order: { id: ASC }) {
| id
| name
| }
| }
| }
""".trimMargin()
}
fun buildMangaDetailsQueryPayload(id: Int) = buildJsonObject {
put("operationName", "project")
put("query", MANGA_DETAILS_QUERY)
putJsonObject("variables") {
put("id", id)
}
}
val PAGES_QUERY = buildQuery {
"""
| query getChapter(%id: String!) {
| getChapters(
| orders: {
| orders: { or: ASC, field: "Chapter.id" }
| }
| filters: {
| operator: AND,
| filters: [
| { op: EQ, field: "Chapter.id", values: [%id] }
| ],
| childExpressions: {
| operator: AND,
| filters: {
| op: GE,
| field: "Project.id",
| relationField: "Chapter.project",
| values: ["1"]
| }
| }
| }
| ) {
| chapters {
| id
| images
| project { id }
| }
| }
| }
""".trimMargin()
}
fun buildPagesQueryPayload(id: String) = buildJsonObject {
put("operationName", "getChapter")
put("query", PAGES_QUERY)
putJsonObject("variables") {
put("id", id)
}
}