Fix AS not working due to website redesign. (#9550)

This commit is contained in:
Alessandro Jean 2021-10-20 08:17:50 -03:00 committed by GitHub
parent 652e61dfef
commit e7853ca2ae
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
19 changed files with 491 additions and 23 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

View File

@ -1,22 +0,0 @@
package eu.kanade.tachiyomi.extension.pt.argosscan
import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor
import eu.kanade.tachiyomi.multisrc.madara.Madara
import okhttp3.OkHttpClient
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
class ArgosScan : Madara(
"Argos Scan",
"https://argosscan.com",
"pt-BR",
SimpleDateFormat("dd 'de' MMMM 'de' yyyy", Locale("pt", "BR"))
) {
override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build()
override fun popularMangaSelector() = "div.page-item-detail.manga"
}

View File

@ -35,7 +35,6 @@ class MadaraGenerator : ThemeSourceGenerator {
SingleLang("Anisa Manga", "https://anisamanga.com", "tr"),
SingleLang("ApollComics", "https://apollcomics.xyz", "es", overrideVersionCode = 1),
SingleLang("ArazNovel", "https://www.araznovel.com", "tr", overrideVersionCode = 2),
SingleLang("Argos Scan", "https://argosscan.com", "pt-BR", overrideVersionCode = 3),
SingleLang("Arthur Scan", "https://arthurscan.xyz", "pt-BR", overrideVersionCode = 4),
SingleLang("Astral Library", "https://www.astrallibrary.net", "en", overrideVersionCode = 2),
SingleLang("Asura Raw", "https://asuraraw.com", "en", overrideVersionCode = 1),

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest package="eu.kanade.tachiyomi.extension" />

View File

@ -0,0 +1,16 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext {
extName = 'Argos Scan'
pkgNameSuffix = 'pt.argosscan'
extClass = '.ArgosScan'
extVersionCode = 15
}
dependencies {
implementation project(':lib-ratelimit')
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 47 KiB

View File

@ -0,0 +1,218 @@
package eu.kanade.tachiyomi.extension.pt.argosscan
import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.asObservableSuccess
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.HttpSource
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.add
import kotlinx.serialization.json.decodeFromJsonElement
import kotlinx.serialization.json.jsonArray
import kotlinx.serialization.json.jsonObject
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.RequestBody.Companion.toRequestBody
import okhttp3.Response
import rx.Observable
import uy.kohesive.injekt.injectLazy
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
class ArgosScan : HttpSource() {
// Website changed from Madara to a custom CMS.
override val versionId = 2
override val name = "Argos Scan"
override val baseUrl = "http://argosscan.com"
override val lang = "pt-BR"
override val supportsLatest = true
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
.build()
private val json: Json by injectLazy()
private fun genericMangaFromObject(project: ArgosProjectDto): SManga = SManga.create().apply {
title = project.name!!
url = "/obras/${project.id}"
thumbnail_url = "$baseUrl/images/${project.id}/${project.cover!!}"
}
override fun popularMangaRequest(page: Int): Request {
val payload = buildPopularQueryPayload(page)
val body = payload.toString().toRequestBody(JSON_MEDIA_TYPE)
val newHeaders = headersBuilder()
.add("Content-Length", body.contentLength().toString())
.add("Content-Type", body.contentType().toString())
.build()
return POST(GRAPHQL_URL, newHeaders, body)
}
override fun popularMangaParse(response: Response): MangasPage {
val result = json.parseToJsonElement(response.body!!.string()).jsonObject
val projectList = result["data"]!!.jsonObject["getProjects"]!!
.let { json.decodeFromJsonElement<ArgosProjectListDto>(it) }
val mangaList = projectList.projects
.map(::genericMangaFromObject)
val hasNextPage = projectList.currentPage < projectList.totalPages
return MangasPage(mangaList, hasNextPage)
}
override fun latestUpdatesRequest(page: Int): Request {
val payload = buildLatestQueryPayload(page)
val body = payload.toString().toRequestBody(JSON_MEDIA_TYPE)
val newHeaders = headersBuilder()
.add("Content-Length", body.contentLength().toString())
.add("Content-Type", body.contentType().toString())
.build()
return POST(GRAPHQL_URL, newHeaders, body)
}
override fun latestUpdatesParse(response: Response): MangasPage = popularMangaParse(response)
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val payload = buildSearchQueryPayload(query, page)
val body = payload.toString().toRequestBody(JSON_MEDIA_TYPE)
val newHeaders = headersBuilder()
.add("Content-Length", body.contentLength().toString())
.add("Content-Type", body.contentType().toString())
.build()
return POST(GRAPHQL_URL, newHeaders, body)
}
override fun searchMangaParse(response: Response): MangasPage = popularMangaParse(response)
// Workaround to allow "Open in browser" use the real URL.
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
return client.newCall(mangaDetailsApiRequest(manga))
.asObservableSuccess()
.map { response ->
mangaDetailsParse(response).apply { initialized = true }
}
}
private fun mangaDetailsApiRequest(manga: SManga): Request {
val mangaId = manga.url.substringAfter("obras/").toInt()
val payload = buildMangaDetailsQueryPayload(mangaId)
val body = payload.toString().toRequestBody(JSON_MEDIA_TYPE)
val newHeaders = headersBuilder()
.add("Content-Length", body.contentLength().toString())
.add("Content-Type", body.contentType().toString())
.build()
return POST(GRAPHQL_URL, newHeaders, body)
}
override fun mangaDetailsParse(response: Response): SManga = SManga.create().apply {
val result = json.parseToJsonElement(response.body!!.string()).jsonObject
val project = result["data"]!!.jsonObject["project"]!!.jsonObject
.let { json.decodeFromJsonElement<ArgosProjectDto>(it) }
title = project.name!!
thumbnail_url = "$baseUrl/images/${project.id}/${project.cover!!}"
description = project.description.orEmpty()
author = project.authors.orEmpty().joinToString(", ")
status = SManga.ONGOING
genre = project.tags.orEmpty().joinToString(", ") { it.name }
}
override fun chapterListRequest(manga: SManga): Request = mangaDetailsApiRequest(manga)
override fun chapterListParse(response: Response): List<SChapter> {
val result = json.parseToJsonElement(response.body!!.string()).jsonObject
val project = result["data"]!!.jsonObject["project"]!!.jsonObject
.let { json.decodeFromJsonElement<ArgosProjectDto>(it) }
return project.chapters.map(::chapterFromObject)
}
private fun chapterFromObject(chapter: ArgosChapterDto): SChapter = SChapter.create().apply {
name = chapter.title!!
chapter_number = chapter.number?.toFloat() ?: -1f
scanlator = this@ArgosScan.name
date_upload = chapter.createAt!!.toDate()
url = "/leitor/${chapter.id}"
}
override fun pageListRequest(chapter: SChapter): Request {
val chapterId = chapter.url.substringAfter("leitor/")
val payload = buildPagesQueryPayload(chapterId)
val body = payload.toString().toRequestBody(JSON_MEDIA_TYPE)
val newHeaders = headersBuilder()
.add("Content-Length", body.contentLength().toString())
.add("Content-Type", body.contentType().toString())
.build()
return POST(GRAPHQL_URL, newHeaders, body)
}
override fun pageListParse(response: Response): List<Page> {
val result = json.parseToJsonElement(response.body!!.string()).jsonObject
val chapterDto = result["data"]!!.jsonObject["getChapters"]!!.jsonObject["chapters"]!!.jsonArray[0]
.let { json.decodeFromJsonElement<ArgosChapterDto>(it) }
val referer = "$baseUrl/leitor/${chapterDto.id}"
return chapterDto.images.orEmpty().mapIndexed { i, page ->
Page(i, referer, "$baseUrl/images/${chapterDto.project!!.id}/$page")
}
}
override fun imageUrlParse(response: Response): String = ""
override fun imageRequest(page: Page): Request {
val newHeaders = headersBuilder()
.set("Referer", page.url)
.build()
return GET(page.imageUrl!!, newHeaders)
}
private fun String.toDate(): Long {
return runCatching { DATE_PARSER.parse(this)?.time }
.getOrNull() ?: 0L
}
companion object {
private const val GRAPHQL_URL = "https://argosscan.com/graphql"
private val JSON_MEDIA_TYPE = "application/json; charset=utf-8".toMediaTypeOrNull()
private val DATE_PARSER by lazy {
SimpleDateFormat("yyyy-MM-dd", Locale("pt", "BR"))
}
}
}

View File

@ -0,0 +1,42 @@
package eu.kanade.tachiyomi.extension.pt.argosscan
import kotlinx.serialization.SerialName
import kotlinx.serialization.Serializable
@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: Int = 0,
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

@ -0,0 +1,213 @@
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 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 buildLatestQueryPayload(page: Int) = buildJsonObject {
put("operationName", "getProjects")
put("query", POPULAR_QUERY)
putJsonObject("variables") {
putJsonObject("filters") {
putJsonObject("childExpressions") {
putJsonObject("filters") {
put("field", "Chapter.id")
put("op", "GE")
put("relationField", "Project.chapters")
putJsonArray("values") {
add("1")
}
}
put("operator", "AND")
}
put("operator", "AND")
}
putJsonObject("orders") {
putJsonArray("orders") {
addJsonObject {
put("field", "Chapter.createAt")
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: { id: 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)
}
}