ArgosScan: Change CMS (#6931)
* Change CMS * Use sortedByDescend Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com> --------- Co-authored-by: AwkwardPeak7 <48650614+AwkwardPeak7@users.noreply.github.com>
This commit is contained in:
		
							parent
							
								
									06dd598b45
								
							
						
					
					
						commit
						f72e042cce
					
				@ -1,7 +1,7 @@
 | 
			
		||||
ext {
 | 
			
		||||
    extName = 'Argos Scan'
 | 
			
		||||
    extClass = '.ArgosScan'
 | 
			
		||||
    extVersionCode = 23
 | 
			
		||||
    extVersionCode = 24
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
apply from: "$rootDir/common.gradle"
 | 
			
		||||
 | 
			
		||||
@ -1,374 +1,134 @@
 | 
			
		||||
package eu.kanade.tachiyomi.extension.pt.argosscan
 | 
			
		||||
 | 
			
		||||
import android.app.Application
 | 
			
		||||
import android.content.SharedPreferences
 | 
			
		||||
import android.text.InputType
 | 
			
		||||
import androidx.preference.EditTextPreference
 | 
			
		||||
import androidx.preference.PreferenceScreen
 | 
			
		||||
import eu.kanade.tachiyomi.network.GET
 | 
			
		||||
import eu.kanade.tachiyomi.network.POST
 | 
			
		||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
 | 
			
		||||
import eu.kanade.tachiyomi.source.ConfigurableSource
 | 
			
		||||
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.decodeFromString
 | 
			
		||||
import kotlinx.serialization.json.Json
 | 
			
		||||
import kotlinx.serialization.json.JsonElement
 | 
			
		||||
import kotlinx.serialization.json.decodeFromJsonElement
 | 
			
		||||
import kotlinx.serialization.json.jsonArray
 | 
			
		||||
import kotlinx.serialization.json.jsonObject
 | 
			
		||||
import kotlinx.serialization.json.jsonPrimitive
 | 
			
		||||
import okhttp3.Headers
 | 
			
		||||
import okhttp3.Interceptor
 | 
			
		||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
 | 
			
		||||
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
 | 
			
		||||
import okhttp3.HttpUrl.Companion.toHttpUrl
 | 
			
		||||
import okhttp3.OkHttpClient
 | 
			
		||||
import okhttp3.Request
 | 
			
		||||
import okhttp3.RequestBody.Companion.toRequestBody
 | 
			
		||||
import okhttp3.Response
 | 
			
		||||
import uy.kohesive.injekt.Injekt
 | 
			
		||||
import uy.kohesive.injekt.api.get
 | 
			
		||||
import uy.kohesive.injekt.injectLazy
 | 
			
		||||
import org.jsoup.nodes.Document
 | 
			
		||||
import org.jsoup.nodes.Element
 | 
			
		||||
import java.io.IOException
 | 
			
		||||
import java.text.SimpleDateFormat
 | 
			
		||||
import java.util.Locale
 | 
			
		||||
import java.util.concurrent.TimeUnit
 | 
			
		||||
 | 
			
		||||
class ArgosScan : HttpSource(), ConfigurableSource {
 | 
			
		||||
 | 
			
		||||
    // Website changed from Madara to a custom CMS.
 | 
			
		||||
    override val versionId = 2
 | 
			
		||||
class ArgosScan : ParsedHttpSource() {
 | 
			
		||||
 | 
			
		||||
    override val name = "Argos Scan"
 | 
			
		||||
 | 
			
		||||
    override val baseUrl = "http://argosscan.com"
 | 
			
		||||
    override val baseUrl = "https://argoscomics.online"
 | 
			
		||||
 | 
			
		||||
    override val lang = "pt-BR"
 | 
			
		||||
 | 
			
		||||
    override val supportsLatest = false
 | 
			
		||||
 | 
			
		||||
    override val client: OkHttpClient = network.cloudflareClient.newBuilder()
 | 
			
		||||
        .addInterceptor(::loginIntercept)
 | 
			
		||||
        .rateLimit(1, 2, TimeUnit.SECONDS)
 | 
			
		||||
        .addInterceptor { chain ->
 | 
			
		||||
            val response = chain.proceed(chain.request())
 | 
			
		||||
            if (response.request.url.pathSegments.any { it.equals("pagina-de-login", true) }) {
 | 
			
		||||
                throw IOException("Faça login na WebView")
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            response
 | 
			
		||||
        }
 | 
			
		||||
        .build()
 | 
			
		||||
 | 
			
		||||
    private val json: Json by injectLazy()
 | 
			
		||||
    // Website changed custom CMS.
 | 
			
		||||
    override val versionId = 3
 | 
			
		||||
 | 
			
		||||
    private val preferences: SharedPreferences by lazy {
 | 
			
		||||
        Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
 | 
			
		||||
    }
 | 
			
		||||
    // ============================ Popular ======================================
 | 
			
		||||
    override fun popularMangaRequest(page: Int) = GET(baseUrl, headers)
 | 
			
		||||
 | 
			
		||||
    private var token: String? = null
 | 
			
		||||
    override fun popularMangaSelector() = ".card__main._grid:not(:has(a[href*=novel]))"
 | 
			
		||||
 | 
			
		||||
    override fun headersBuilder(): Headers.Builder = Headers.Builder()
 | 
			
		||||
        .add("Token", "")
 | 
			
		||||
 | 
			
		||||
    private fun genericMangaFromObject(project: ArgosProjectDto): SManga = SManga.create().apply {
 | 
			
		||||
        title = project.name!!
 | 
			
		||||
        url = "/obras/${project.id}"
 | 
			
		||||
        thumbnail_url = if (project.cover!! == "default.jpg") {
 | 
			
		||||
            "$baseUrl/img/default.jpg"
 | 
			
		||||
        } else {
 | 
			
		||||
            "$baseUrl/images/${project.id}/${project.cover}"
 | 
			
		||||
    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 popularMangaRequest(page: Int): Request {
 | 
			
		||||
        val payload = buildPopularQueryPayload(page)
 | 
			
		||||
    override fun popularMangaNextPageSelector() = null
 | 
			
		||||
 | 
			
		||||
        val body = payload.toString().toRequestBody(JSON_MEDIA_TYPE)
 | 
			
		||||
    // ============================ Latest ======================================
 | 
			
		||||
 | 
			
		||||
        val newHeaders = headersBuilder()
 | 
			
		||||
            .add("Content-Length", body.contentLength().toString())
 | 
			
		||||
            .add("Content-Type", body.contentType().toString())
 | 
			
		||||
            .build()
 | 
			
		||||
    override fun latestUpdatesRequest(page: Int) = throw UnsupportedOperationException()
 | 
			
		||||
 | 
			
		||||
        return POST(GRAPHQL_URL, newHeaders, body)
 | 
			
		||||
    }
 | 
			
		||||
    override fun latestUpdatesSelector() = throw UnsupportedOperationException()
 | 
			
		||||
 | 
			
		||||
    override fun popularMangaParse(response: Response): MangasPage {
 | 
			
		||||
        val result = response.parseAs<ArgosResponseDto<ArgosProjectListDto>>()
 | 
			
		||||
    override fun latestUpdatesFromElement(element: Element) = throw UnsupportedOperationException()
 | 
			
		||||
 | 
			
		||||
        if (result.data == null) {
 | 
			
		||||
            throw Exception(REQUEST_ERROR)
 | 
			
		||||
        }
 | 
			
		||||
    override fun latestUpdatesNextPageSelector() = throw UnsupportedOperationException()
 | 
			
		||||
 | 
			
		||||
        val projectList = result.data["getProjects"]!!
 | 
			
		||||
 | 
			
		||||
        val mangaList = projectList.projects
 | 
			
		||||
            .map(::genericMangaFromObject)
 | 
			
		||||
 | 
			
		||||
        val hasNextPage = projectList.currentPage < projectList.totalPages
 | 
			
		||||
 | 
			
		||||
        return MangasPage(mangaList, hasNextPage)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun latestUpdatesRequest(page: Int): Request = throw UnsupportedOperationException()
 | 
			
		||||
 | 
			
		||||
    override fun latestUpdatesParse(response: Response): MangasPage = throw UnsupportedOperationException()
 | 
			
		||||
    // ============================ Search ======================================
 | 
			
		||||
 | 
			
		||||
    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())
 | 
			
		||||
        val url = baseUrl.toHttpUrl().newBuilder()
 | 
			
		||||
            .addQueryParameter("s", query)
 | 
			
		||||
            .build()
 | 
			
		||||
 | 
			
		||||
        return POST(GRAPHQL_URL, newHeaders, body)
 | 
			
		||||
        return GET(url, headers)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun searchMangaParse(response: Response): MangasPage = popularMangaParse(response)
 | 
			
		||||
    override fun searchMangaSelector() = popularMangaSelector()
 | 
			
		||||
 | 
			
		||||
    override fun getMangaUrl(manga: SManga): String = baseUrl + manga.url
 | 
			
		||||
    override fun searchMangaFromElement(element: Element) = popularMangaFromElement(element)
 | 
			
		||||
 | 
			
		||||
    override fun mangaDetailsRequest(manga: SManga): Request {
 | 
			
		||||
        val mangaId = manga.url.substringAfter("obras/").toInt()
 | 
			
		||||
    override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
 | 
			
		||||
 | 
			
		||||
        val payload = buildMangaDetailsQueryPayload(mangaId)
 | 
			
		||||
    // ============================ Details =====================================
 | 
			
		||||
 | 
			
		||||
        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 = response.parseAs<ArgosResponseDto<ArgosProjectDto>>()
 | 
			
		||||
 | 
			
		||||
        if (result.data == null) {
 | 
			
		||||
            throw Exception(REQUEST_ERROR)
 | 
			
		||||
    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
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val project = result.data["project"]!!
 | 
			
		||||
 | 
			
		||||
        title = project.name!!
 | 
			
		||||
        thumbnail_url = if (project.cover!! == "default.jpg") {
 | 
			
		||||
            "$baseUrl/img/default.jpg"
 | 
			
		||||
        } else {
 | 
			
		||||
            "$baseUrl/images/${project.id}/${project.cover}"
 | 
			
		||||
        }
 | 
			
		||||
        description = project.description.orEmpty()
 | 
			
		||||
        author = project.authors.orEmpty().joinToString()
 | 
			
		||||
        status = SManga.ONGOING
 | 
			
		||||
        genre = project.tags.orEmpty().sortedBy(ArgosTagDto::name).joinToString { it.name }
 | 
			
		||||
        setUrlWithoutDomain(document.location())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun chapterListRequest(manga: SManga): Request = mangaDetailsRequest(manga)
 | 
			
		||||
    // ============================ Chapter =====================================
 | 
			
		||||
 | 
			
		||||
    override fun chapterListSelector() = ".chapter-group__list li:has(a)"
 | 
			
		||||
 | 
			
		||||
    override fun chapterFromElement(element: Element) = SChapter.create().apply {
 | 
			
		||||
        with(element.selectFirst("a")!!) {
 | 
			
		||||
            name = text()
 | 
			
		||||
            setUrlWithoutDomain(absUrl("href"))
 | 
			
		||||
        }
 | 
			
		||||
        element.selectFirst(".chapter-group__list-item-date")?.attr("datetime")?.let {
 | 
			
		||||
            date_upload = it.parseDate()
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun chapterListParse(response: Response): List<SChapter> {
 | 
			
		||||
        val result = response.parseAs<ArgosResponseDto<ArgosProjectDto>>()
 | 
			
		||||
 | 
			
		||||
        if (result.data == null) {
 | 
			
		||||
            throw Exception(REQUEST_ERROR)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return result.data["project"]!!.chapters.map(::chapterFromObject)
 | 
			
		||||
        return super.chapterListParse(response).sortedByDescending(SChapter::chapter_number)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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}"
 | 
			
		||||
    }
 | 
			
		||||
    // ============================ Pages =======================================
 | 
			
		||||
 | 
			
		||||
    override fun getChapterUrl(chapter: SChapter): String = baseUrl + chapter.url
 | 
			
		||||
 | 
			
		||||
    override fun pageListRequest(chapter: SChapter): Request {
 | 
			
		||||
        if (chapter.url.removePrefix("/leitor/").toIntOrNull() != null) {
 | 
			
		||||
            throw Exception(REFRESH_WARNING)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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 = response.parseAs<JsonElement>().jsonObject
 | 
			
		||||
 | 
			
		||||
        if (result["errors"] != null) {
 | 
			
		||||
            throw Exception(REQUEST_ERROR)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        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 pageListParse(document: Document): List<Page> {
 | 
			
		||||
        return document.select("#chapter-content img").mapIndexed { index, element ->
 | 
			
		||||
            Page(index, imageUrl = element.absUrl("src"))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun imageUrlParse(response: Response): String = ""
 | 
			
		||||
    override fun imageUrlParse(document: Document) = ""
 | 
			
		||||
 | 
			
		||||
    override fun imageRequest(page: Page): Request {
 | 
			
		||||
        val newHeaders = headersBuilder()
 | 
			
		||||
            .set("Referer", page.url)
 | 
			
		||||
            .build()
 | 
			
		||||
    // ============================== Utilities ==================================
 | 
			
		||||
 | 
			
		||||
        return GET(page.imageUrl!!, newHeaders)
 | 
			
		||||
    private fun String.parseDate(): Long {
 | 
			
		||||
        return try { dateFormat.parse(this.trim())!!.time } catch (_: Exception) { 0L }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun setupPreferenceScreen(screen: PreferenceScreen) {
 | 
			
		||||
        val emailPref = EditTextPreference(screen.context).apply {
 | 
			
		||||
            key = EMAIL_PREF_KEY
 | 
			
		||||
            title = EMAIL_PREF_TITLE
 | 
			
		||||
            summary = EMAIL_PREF_SUMMARY
 | 
			
		||||
            setDefaultValue("")
 | 
			
		||||
            dialogTitle = EMAIL_PREF_TITLE
 | 
			
		||||
            dialogMessage = EMAIL_PREF_DIALOG
 | 
			
		||||
 | 
			
		||||
            setOnBindEditTextListener {
 | 
			
		||||
                it.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            setOnPreferenceChangeListener { _, newValue ->
 | 
			
		||||
                token = null
 | 
			
		||||
 | 
			
		||||
                preferences.edit()
 | 
			
		||||
                    .putString(EMAIL_PREF_KEY, newValue as String)
 | 
			
		||||
                    .commit()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val passwordPref = EditTextPreference(screen.context).apply {
 | 
			
		||||
            key = PASSWORD_PREF_KEY
 | 
			
		||||
            title = PASSWORD_PREF_TITLE
 | 
			
		||||
            summary = PASSWORD_PREF_SUMMARY
 | 
			
		||||
            setDefaultValue("")
 | 
			
		||||
            dialogTitle = PASSWORD_PREF_TITLE
 | 
			
		||||
            dialogMessage = PASSWORD_PREF_DIALOG
 | 
			
		||||
 | 
			
		||||
            setOnBindEditTextListener {
 | 
			
		||||
                it.inputType = InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_PASSWORD
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            setOnPreferenceChangeListener { _, newValue ->
 | 
			
		||||
                token = null
 | 
			
		||||
 | 
			
		||||
                preferences.edit()
 | 
			
		||||
                    .putString(PASSWORD_PREF_KEY, newValue as String)
 | 
			
		||||
                    .commit()
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        screen.addPreference(emailPref)
 | 
			
		||||
        screen.addPreference(passwordPref)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun loginIntercept(chain: Interceptor.Chain): Response {
 | 
			
		||||
        if (chain.request().url.toString().contains("graphql").not()) {
 | 
			
		||||
            return chain.proceed(chain.request())
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        val email = preferences.getString(EMAIL_PREF_KEY, "")
 | 
			
		||||
        val password = preferences.getString(PASSWORD_PREF_KEY, "")
 | 
			
		||||
 | 
			
		||||
        if (!email.isNullOrEmpty() && !password.isNullOrEmpty() && token.isNullOrEmpty()) {
 | 
			
		||||
            val loginResponse = chain.proceed(loginRequest(email, password))
 | 
			
		||||
 | 
			
		||||
            if (!loginResponse.headers["Content-Type"].orEmpty().contains("application/json")) {
 | 
			
		||||
                loginResponse.close()
 | 
			
		||||
 | 
			
		||||
                throw IOException(CLOUDFLARE_ERROR)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            val loginResult = json.parseToJsonElement(loginResponse.body.string()).jsonObject
 | 
			
		||||
 | 
			
		||||
            if (loginResult["errors"] != null) {
 | 
			
		||||
                loginResponse.close()
 | 
			
		||||
 | 
			
		||||
                val errorMessage = runCatching {
 | 
			
		||||
                    loginResult["errors"]!!.jsonArray[0].jsonObject["message"]?.jsonPrimitive?.content
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                throw IOException(errorMessage.getOrNull() ?: REQUEST_ERROR)
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            token = loginResult["data"]!!
 | 
			
		||||
                .jsonObject["login"]!!
 | 
			
		||||
                .jsonObject["token"]!!
 | 
			
		||||
                .jsonPrimitive.content
 | 
			
		||||
 | 
			
		||||
            loginResponse.close()
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!token.isNullOrEmpty()) {
 | 
			
		||||
            val authorizedRequest = chain.request().newBuilder()
 | 
			
		||||
                .addHeader("Authorization", "Bearer $token")
 | 
			
		||||
                .build()
 | 
			
		||||
 | 
			
		||||
            return chain.proceed(authorizedRequest)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return chain.proceed(chain.request())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun loginRequest(email: String, password: String): Request {
 | 
			
		||||
        val payload = buildLoginMutationQueryPayload(email, password)
 | 
			
		||||
 | 
			
		||||
        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)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private inline fun <reified T> Response.parseAs(): T = use {
 | 
			
		||||
        json.decodeFromString(it.body.string())
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    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 const val EMAIL_PREF_KEY = "email"
 | 
			
		||||
        private const val EMAIL_PREF_TITLE = "E-mail"
 | 
			
		||||
        private const val EMAIL_PREF_SUMMARY = "Defina o e-mail de sua conta no site."
 | 
			
		||||
        private const val EMAIL_PREF_DIALOG = "Deixe em branco caso o site torne o login opcional."
 | 
			
		||||
 | 
			
		||||
        private const val PASSWORD_PREF_KEY = "password"
 | 
			
		||||
        private const val PASSWORD_PREF_TITLE = "Senha"
 | 
			
		||||
        private const val PASSWORD_PREF_SUMMARY = "Defina a senha de sua conta no site."
 | 
			
		||||
        private const val PASSWORD_PREF_DIALOG = EMAIL_PREF_DIALOG
 | 
			
		||||
 | 
			
		||||
        private const val CLOUDFLARE_ERROR = "Falha ao contornar o Cloudflare."
 | 
			
		||||
        private const val REQUEST_ERROR = "Erro na requisição. Tente novamente mais tarde."
 | 
			
		||||
        private const val REFRESH_WARNING = "Atualize a lista de capítulos para atualizar os IDs."
 | 
			
		||||
 | 
			
		||||
        private val JSON_MEDIA_TYPE = "application/json; charset=utf-8".toMediaTypeOrNull()
 | 
			
		||||
 | 
			
		||||
        private val DATE_PARSER by lazy {
 | 
			
		||||
            SimpleDateFormat("yyyy-MM-dd", Locale("pt", "BR"))
 | 
			
		||||
        }
 | 
			
		||||
        val dateFormat = SimpleDateFormat("yyyy-MM-dd", Locale.ROOT)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user