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 {
extName = 'Argos Scan'
extClass = '.ArgosScan'
extVersionCode = 24
extVersionCode = 25
}
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.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 keiyoushi.utils.parseAs
import keiyoushi.utils.tryParse
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.OkHttpClient
import okhttp3.Request
@ -29,7 +33,7 @@ class ArgosScan : ParsedHttpSource() {
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
.addInterceptor { chain ->
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")
}
@ -43,18 +47,22 @@ class ArgosScan : ParsedHttpSource() {
// ============================ Popular ======================================
override fun popularMangaRequest(page: Int) = GET(baseUrl, headers)
override fun popularMangaSelector() = ".card__main._grid:not(:has(a[href*=novel]))"
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 popularMangaSelector() = throw UnsupportedOperationException()
override fun popularMangaFromElement(element: Element) = throw UnsupportedOperationException()
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 ======================================
override fun latestUpdatesRequest(page: Int) = throw UnsupportedOperationException()
@ -83,40 +91,34 @@ class ArgosScan : ParsedHttpSource() {
// ============================ Details =====================================
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
title = document.selectFirst("h1")!!.text()
thumbnail_url = document.selectFirst("img.story__thumbnail-image")?.absUrl("src")
description = document.selectFirst(".story__summary p")?.text()
document.selectFirst(".story__status")?.let {
status = when (it.text().trim().lowercase()) {
"em andamento" -> SManga.ONGOING
else -> SManga.UNKNOWN
with(document) {
title = selectFirst(".content h2")!!.text()
thumbnail_url = selectFirst(".trailer-box img")?.absUrl("src")
description = selectFirst(".content p")?.text()
selectFirst("section[data-status]")?.attr("data-status")?.let {
status = it.toStatus()
}
genre = select("h6:contains(Tags) + h6 > span").joinToString { it.text() }
}
setUrlWithoutDomain(document.location())
}
// ============================ Chapter =====================================
override fun chapterListSelector() = ".chapter-group__list li:has(a)"
override fun chapterListSelector() = ".manga-chapter"
override fun chapterFromElement(element: Element) = SChapter.create().apply {
with(element.selectFirst("a")!!) {
name = text()
setUrlWithoutDomain(absUrl("href"))
name = element.selectFirst("h5")!!.text()
element.selectFirst("h6")?.let {
date_upload = dateFormat.tryParse(it.text())
}
element.selectFirst(".chapter-group__list-item-date")?.attr("datetime")?.let {
date_upload = it.parseDate()
}
}
override fun chapterListParse(response: Response): List<SChapter> {
return super.chapterListParse(response).sortedByDescending(SChapter::chapter_number)
setUrlWithoutDomain(element.selectFirst("a")!!.absUrl("href"))
}
// ============================ Pages =======================================
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"))
}
}
@ -125,10 +127,8 @@ class ArgosScan : ParsedHttpSource() {
// ============================== Utilities ==================================
private fun String.parseDate(): Long {
return try { dateFormat.parse(this.trim())!!.time } catch (_: Exception) { 0L }
}
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
import eu.kanade.tachiyomi.source.model.SManga
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@Serializable
data class ArgosResponseDto<T>(
val data: Map<String, T>? = null,
)
class MangaDto(
@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
data class ArgosProjectListDto(
val count: Int = 0,
val currentPage: Int = 0,
val limit: Int = 0,
val projects: List<ArgosProjectDto> = emptyList(),
val totalPages: Int = 0,
)
@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,
class DetailsDto(
val title: Map<String, String>,
val description: Map<String, String> = emptyMap(),
val status: String,
@SerialName("tags")
val genres: List<String> = emptyList(),
)

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)
}
}