Remove some sources that are in a cat and mouse game. (#7065)
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="eu.kanade.tachiyomi.extension" />
|
|
@ -1,16 +0,0 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
ext {
|
||||
extName = 'HQ Dragon'
|
||||
pkgNameSuffix = 'pt.hqdragon'
|
||||
extClass = '.HQDragon'
|
||||
extVersionCode = 4
|
||||
libVersion = '1.2'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':lib-ratelimit')
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
Before Width: | Height: | Size: 4.0 KiB |
Before Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 5.8 KiB |
Before Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 98 KiB |
|
@ -1,206 +0,0 @@
|
|||
package eu.kanade.tachiyomi.extension.pt.hqdragon
|
||||
|
||||
import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
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 okhttp3.FormBody
|
||||
import okhttp3.Headers
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import rx.Observable
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class HQDragon : ParsedHttpSource() {
|
||||
|
||||
override val name = "HQ Dragon"
|
||||
|
||||
override val baseUrl = "https://hqdragon.com"
|
||||
|
||||
override val lang = "pt-BR"
|
||||
|
||||
override val supportsLatest = true
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
|
||||
.build()
|
||||
|
||||
override fun headersBuilder(): Headers.Builder = Headers.Builder()
|
||||
.add("Accept", ACCEPT)
|
||||
.add("Accept-Language", ACCEPT_LANGUAGE)
|
||||
.add("Referer", "$baseUrl/")
|
||||
|
||||
// Popular
|
||||
|
||||
// Top 10
|
||||
override fun popularMangaRequest(page: Int): Request {
|
||||
return GET(baseUrl, headers)
|
||||
}
|
||||
|
||||
override fun popularMangaParse(response: Response): MangasPage {
|
||||
val results = super.popularMangaParse(response)
|
||||
|
||||
if (results.mangas.isEmpty()) {
|
||||
throw Exception(BLOCK_MESSAGE)
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
override fun popularMangaSelector() = "h4:contains(Top 10) + ol.mb-0 li a"
|
||||
|
||||
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||
title = element.text()
|
||||
setUrlWithoutDomain(element.attr("href"))
|
||||
}
|
||||
|
||||
override fun popularMangaNextPageSelector(): String? = null
|
||||
|
||||
// Latest
|
||||
|
||||
override fun fetchLatestUpdates(page: Int): Observable<MangasPage> {
|
||||
return super.fetchLatestUpdates(page)
|
||||
.map { results -> results.copy(hasNextPage = page < 5) }
|
||||
}
|
||||
|
||||
override fun latestUpdatesRequest(page: Int): Request {
|
||||
val formBody = FormBody.Builder()
|
||||
.add("pagina", page.toString())
|
||||
.build()
|
||||
|
||||
val headers = headersBuilder()
|
||||
.add("Content-Length", formBody.contentLength().toString())
|
||||
.add("Content-Type", formBody.contentType().toString())
|
||||
.add("Origin", baseUrl)
|
||||
.add("X-Requested-With", "XMLHttpRequest")
|
||||
.set("Accept", "*/*")
|
||||
.build()
|
||||
|
||||
return POST("$baseUrl/assets/php/index_paginar.php", headers, formBody)
|
||||
}
|
||||
|
||||
override fun latestUpdatesParse(response: Response): MangasPage {
|
||||
val results = super.latestUpdatesParse(response)
|
||||
|
||||
if (results.mangas.isEmpty()) {
|
||||
throw Exception(BLOCK_MESSAGE)
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
override fun latestUpdatesSelector() = "a:has(img)"
|
||||
|
||||
override fun latestUpdatesFromElement(element: Element): SManga = SManga.create().apply {
|
||||
val image = element.select("img").first()
|
||||
|
||||
title = image.attr("alt")
|
||||
thumbnail_url = image.attr("abs:src")
|
||||
setUrlWithoutDomain(element.attr("href"))
|
||||
}
|
||||
|
||||
override fun latestUpdatesNextPageSelector(): String? = null
|
||||
|
||||
// Search
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
val url = "$baseUrl/pesquisa".toHttpUrlOrNull()!!.newBuilder()
|
||||
.addQueryParameter("titulo", query)
|
||||
|
||||
return GET(url.toString(), headers)
|
||||
}
|
||||
|
||||
override fun searchMangaParse(response: Response): MangasPage {
|
||||
val results = super.searchMangaParse(response)
|
||||
|
||||
if (results.mangas.isEmpty()) {
|
||||
throw Exception(BLOCK_MESSAGE)
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
override fun searchMangaSelector() = "div.col-sm-6.col-md-3:has(img.img-thumbnail)"
|
||||
|
||||
override fun searchMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||
val link = element.select("a + a").first()
|
||||
|
||||
title = link.text()
|
||||
thumbnail_url = element.select("img").first().attr("abs:src")
|
||||
setUrlWithoutDomain(link.attr("href"))
|
||||
}
|
||||
|
||||
override fun searchMangaNextPageSelector(): String? = null
|
||||
|
||||
// Manga summary page
|
||||
|
||||
override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
|
||||
val infoElement = document.select("div.blog-post div.row").firstOrNull()
|
||||
?: throw Exception(BLOCK_MESSAGE)
|
||||
|
||||
title = infoElement.select("h3").first().text()
|
||||
author = infoElement.select("p:contains(Editora:)").first().textWithoutLabel()
|
||||
status = infoElement.select("p:contains(Status:) span").first().text().toStatus()
|
||||
description = infoElement.select("p:contains(Sinopse:)").first().ownText()
|
||||
thumbnail_url = infoElement.select("div.col-md-4 .img-fluid").first().attr("src")
|
||||
}
|
||||
|
||||
// Chapters
|
||||
|
||||
override fun chapterListSelector() = "table.table tr a"
|
||||
|
||||
override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
|
||||
name = element.text().replace("Ler ", "")
|
||||
setUrlWithoutDomain(element.attr("href"))
|
||||
}
|
||||
|
||||
// Pages
|
||||
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
return document.select("img.img-responsive.img-manga")
|
||||
.filter { it.attr("src").contains("/leitor/") }
|
||||
.mapIndexed { i, element ->
|
||||
Page(i, document.location(), element.absUrl("src"))
|
||||
}
|
||||
}
|
||||
|
||||
override fun imageUrlParse(document: Document) = ""
|
||||
|
||||
override fun imageRequest(page: Page): Request {
|
||||
val newHeaders = headersBuilder()
|
||||
.set("Accept", ACCEPT_IMAGE)
|
||||
.set("Referer", page.url)
|
||||
.build()
|
||||
|
||||
return GET(page.imageUrl!!, newHeaders)
|
||||
}
|
||||
|
||||
private fun Element.textWithoutLabel(): String = text()!!.substringAfter(":").trim()
|
||||
|
||||
private fun String.toStatus(): Int = when {
|
||||
contains("Ativo") -> SManga.ONGOING
|
||||
contains("Completo") -> SManga.COMPLETED
|
||||
else -> SManga.UNKNOWN
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val ACCEPT = "text/html,application/xhtml+xml,application/xml;q=0.9," +
|
||||
"image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"
|
||||
private const val ACCEPT_IMAGE = "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8"
|
||||
private const val ACCEPT_LANGUAGE = "pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7,es;q=0.6,gl;q=0.5"
|
||||
private const val USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
|
||||
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36"
|
||||
|
||||
private const val BLOCK_MESSAGE = "O site está bloqueando o Tachiyomi. " +
|
||||
"Migre para outra fonte caso o problema persistir."
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="eu.kanade.tachiyomi.extension" />
|
|
@ -1,16 +0,0 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
ext {
|
||||
extName = 'Mangá Host'
|
||||
pkgNameSuffix = 'pt.mangahost'
|
||||
extClass = '.MangaHost'
|
||||
extVersionCode = 24
|
||||
libVersion = '1.2'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':lib-ratelimit')
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
Before Width: | Height: | Size: 2.8 KiB |
Before Width: | Height: | Size: 1.6 KiB |
Before Width: | Height: | Size: 3.9 KiB |
Before Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 49 KiB |
|
@ -1,288 +0,0 @@
|
|||
package eu.kanade.tachiyomi.extension.pt.mangahost
|
||||
|
||||
import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.asObservable
|
||||
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 okhttp3.Call
|
||||
import okhttp3.Headers
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import org.jsoup.select.Elements
|
||||
import rx.Observable
|
||||
import java.text.ParseException
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class MangaHost : ParsedHttpSource() {
|
||||
|
||||
// Hardcode the id because the name was wrong and the language wasn't specific.
|
||||
override val id: Long = 3926812845500643354
|
||||
|
||||
override val name = "Mangá Host"
|
||||
|
||||
override val baseUrl = "https://mangahostz.com"
|
||||
|
||||
override val lang = "pt-BR"
|
||||
|
||||
override val supportsLatest = true
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.addInterceptor(RateLimitInterceptor(1, 3, TimeUnit.SECONDS))
|
||||
.addInterceptor(::blockMessageIntercept)
|
||||
.build()
|
||||
|
||||
override fun headersBuilder(): Headers.Builder = Headers.Builder()
|
||||
.add("Accept", ACCEPT)
|
||||
.add("Accept-Language", ACCEPT_LANGUAGE)
|
||||
.add("Referer", baseUrl)
|
||||
.add("User-Agent", USER_AGENT)
|
||||
|
||||
private fun genericMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||
val thumbnailEl = element.select("img")
|
||||
val thumbnailAttr = if (thumbnailEl.hasAttr("data-path")) "data-path" else "src"
|
||||
|
||||
title = element.attr("title").withoutLanguage()
|
||||
thumbnail_url = thumbnailEl.attr(thumbnailAttr).toLargeUrl()
|
||||
setUrlWithoutDomain(element.attr("href"))
|
||||
}
|
||||
|
||||
override fun popularMangaRequest(page: Int): Request {
|
||||
val listPath = if (page == 1) "" else "/mais-visualizados/page/${page - 1}"
|
||||
val newHeaders = headersBuilder()
|
||||
.set("Referer", "$baseUrl/mangas$listPath")
|
||||
.build()
|
||||
|
||||
val pageStr = if (page != 1) "/page/$page" else ""
|
||||
return GET("$baseUrl/mangas/mais-visualizados$pageStr", newHeaders)
|
||||
}
|
||||
|
||||
override fun popularMangaParse(response: Response): MangasPage {
|
||||
val results = super.popularMangaParse(response)
|
||||
|
||||
if (results.mangas.isEmpty()) {
|
||||
throw Exception(BLOCK_MESSAGE)
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
override fun popularMangaSelector(): String = "div#dados div.manga-block div.manga-block-left a"
|
||||
|
||||
override fun popularMangaFromElement(element: Element): SManga = genericMangaFromElement(element)
|
||||
|
||||
override fun popularMangaNextPageSelector() = "div.wp-pagenavi:has(a.nextpostslink)"
|
||||
|
||||
override fun latestUpdatesRequest(page: Int): Request {
|
||||
val listPath = if (page == 1) "" else "/lancamentos/page/${page - 1}"
|
||||
val newHeaders = headersBuilder()
|
||||
.set("Referer", baseUrl + listPath)
|
||||
.build()
|
||||
|
||||
val pageStr = if (page != 1) "/page/$page" else ""
|
||||
return GET("$baseUrl/lancamentos$pageStr", newHeaders)
|
||||
}
|
||||
|
||||
override fun latestUpdatesParse(response: Response): MangasPage {
|
||||
val results = super.latestUpdatesParse(response)
|
||||
|
||||
if (results.mangas.isEmpty()) {
|
||||
throw Exception(BLOCK_MESSAGE)
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
override fun latestUpdatesSelector() = "div#dados div.w-row div.column-img a"
|
||||
|
||||
override fun latestUpdatesFromElement(element: Element): SManga = genericMangaFromElement(element)
|
||||
|
||||
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
val url = "$baseUrl/find".toHttpUrlOrNull()!!.newBuilder()
|
||||
.addQueryParameter("this", query)
|
||||
|
||||
return GET(url.toString(), headers)
|
||||
}
|
||||
|
||||
override fun searchMangaSelector() = "table.table-search > tbody > tr > td:eq(0) > a"
|
||||
|
||||
override fun searchMangaFromElement(element: Element): SManga = genericMangaFromElement(element)
|
||||
|
||||
override fun searchMangaNextPageSelector(): String? = null
|
||||
|
||||
/**
|
||||
* The site wrongly return 404 for some titles, even if they are present.
|
||||
* In those cases, the extension will parse the response normally.
|
||||
*/
|
||||
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
|
||||
return client.newCall(mangaDetailsRequest(manga))
|
||||
.asObservableIgnoreCode(404)
|
||||
.map { response ->
|
||||
mangaDetailsParse(response).apply { initialized = true }
|
||||
}
|
||||
}
|
||||
|
||||
override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
|
||||
val infoElement = document.select("div.box-content div.w-row div.w-col:eq(1) article")
|
||||
.firstOrNull() ?: throw Exception(BLOCK_MESSAGE)
|
||||
|
||||
author = infoElement.select("div.text li div:contains(Autor:)").textWithoutLabel()
|
||||
artist = infoElement.select("div.text li div:contains(Arte:)").textWithoutLabel()
|
||||
genre = infoElement.select("h3.subtitle + div.tags a").joinToString { it.text() }
|
||||
description = infoElement.select("div.text div.paragraph").first()?.text()
|
||||
?.substringBefore("Relacionados:")
|
||||
status = infoElement.select("div.text li div:contains(Status:)").text().toStatus()
|
||||
thumbnail_url = document.select("div.box-content div.w-row div.w-col:eq(0) div.widget img")
|
||||
.attr("src")
|
||||
}
|
||||
|
||||
/**
|
||||
* The site wrongly return 404 for some titles, even if they are present.
|
||||
* In those cases, the extension will parse the response normally.
|
||||
*/
|
||||
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
|
||||
return if (manga.status != SManga.LICENSED) {
|
||||
client.newCall(chapterListRequest(manga))
|
||||
.asObservableIgnoreCode(404)
|
||||
.map(::chapterListParse)
|
||||
} else {
|
||||
Observable.error(Exception("Licensed - No chapters to show"))
|
||||
}
|
||||
}
|
||||
|
||||
override fun chapterListParse(response: Response): List<SChapter> {
|
||||
val chapters = super.chapterListParse(response)
|
||||
|
||||
if (chapters.isEmpty()) {
|
||||
throw Exception(BLOCK_MESSAGE)
|
||||
}
|
||||
|
||||
return chapters
|
||||
}
|
||||
|
||||
override fun chapterListSelector(): String =
|
||||
"article section.clearfix div.chapters div.cap div.card.pop"
|
||||
|
||||
override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
|
||||
name = element.select("div.pop-title").text().withoutLanguage()
|
||||
scanlator = element.select("div.pop-content small strong").text()
|
||||
date_upload = element.select("small.clearfix").text()
|
||||
.substringAfter("Adicionado em ")
|
||||
.toDate()
|
||||
chapter_number = element.select("div.pop-title span.btn-caps").text()
|
||||
.toFloatOrNull() ?: 1f
|
||||
setUrlWithoutDomain(element.select("div.tags a").attr("href"))
|
||||
|
||||
if (scanlator!!.split("/").count() >= 5) {
|
||||
val scanlators = scanlator!!.split("/")
|
||||
scanlator = scanlators[0] + " e mais " + (scanlators.count() - 1)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The site wrongly return 404 for some chapters, even if they are present.
|
||||
* In those cases, the extension will parse the response normally.
|
||||
*/
|
||||
override fun fetchPageList(chapter: SChapter): Observable<List<Page>> {
|
||||
return client.newCall(pageListRequest(chapter))
|
||||
.asObservableIgnoreCode(404)
|
||||
.map(::pageListParse)
|
||||
}
|
||||
|
||||
override fun pageListRequest(chapter: SChapter): Request {
|
||||
// Just to prevent the detection of the crawler.
|
||||
val newHeader = headersBuilder()
|
||||
.set("Referer", "$baseUrl${chapter.url}".substringBeforeLast("/"))
|
||||
.build()
|
||||
|
||||
return GET(baseUrl + chapter.url, newHeader)
|
||||
}
|
||||
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
return document.select("div#slider a img")
|
||||
.mapIndexed { i, el -> Page(i, document.location(), el.attr("src")) }
|
||||
}
|
||||
|
||||
override fun imageUrlParse(document: Document) = ""
|
||||
|
||||
override fun imageRequest(page: Page): Request {
|
||||
val newHeaders = headersBuilder()
|
||||
.set("Accept", ACCEPT_IMAGE)
|
||||
.set("Referer", "$baseUrl/")
|
||||
.build()
|
||||
|
||||
return GET(page.imageUrl!!, newHeaders)
|
||||
}
|
||||
|
||||
private fun blockMessageIntercept(chain: Interceptor.Chain): Response {
|
||||
val response = chain.proceed(chain.request())
|
||||
|
||||
if (response.code == 403 || response.code == 1020) {
|
||||
response.close()
|
||||
throw Exception(BLOCK_MESSAGE)
|
||||
}
|
||||
|
||||
return response
|
||||
}
|
||||
|
||||
private fun Call.asObservableIgnoreCode(code: Int): Observable<Response> {
|
||||
return asObservable().doOnNext { response ->
|
||||
if (!response.isSuccessful && response.code != code) {
|
||||
response.close()
|
||||
throw Exception("HTTP error ${response.code}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.toDate(): Long {
|
||||
return try {
|
||||
DATE_FORMAT.parse(this)?.time ?: 0L
|
||||
} catch (e: ParseException) {
|
||||
0L
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.toStatus() = when (this) {
|
||||
"Ativo" -> SManga.ONGOING
|
||||
"Completo" -> SManga.COMPLETED
|
||||
else -> SManga.UNKNOWN
|
||||
}
|
||||
|
||||
private fun String.withoutLanguage(): String = replace(LANG_REGEX, "")
|
||||
|
||||
private fun String.toLargeUrl(): String = replace(IMAGE_REGEX, "_full.")
|
||||
|
||||
private fun Elements.textWithoutLabel(): String = text()!!.substringAfter(":").trim()
|
||||
|
||||
companion object {
|
||||
private const val ACCEPT = "text/html,application/xhtml+xml,application/xml;q=0.9," +
|
||||
"image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"
|
||||
private const val ACCEPT_IMAGE = "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8"
|
||||
private const val ACCEPT_LANGUAGE = "pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7,es;q=0.6,gl;q=0.5"
|
||||
private const val USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
|
||||
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36"
|
||||
|
||||
private val LANG_REGEX = "( )?\\((PT-)?BR\\)".toRegex()
|
||||
private val IMAGE_REGEX = "_(small|medium|xmedium)\\.".toRegex()
|
||||
|
||||
private const val BLOCK_MESSAGE = "O site está bloqueando o Tachiyomi. " +
|
||||
"Migre para outra fonte caso o problema persistir."
|
||||
|
||||
private val DATE_FORMAT by lazy {
|
||||
SimpleDateFormat("MMM dd, yyyy", Locale.ENGLISH)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="eu.kanade.tachiyomi.extension">
|
||||
|
||||
<application>
|
||||
<activity
|
||||
android:name=".pt.unionmangas.UnionMangasUrlActivity"
|
||||
android:excludeFromRecents="true"
|
||||
android:theme="@android:style/Theme.NoDisplay">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.VIEW" />
|
||||
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data
|
||||
android:host="unionleitor.top"
|
||||
android:pathPattern="/perfil-manga/..*"
|
||||
android:scheme="https" />
|
||||
<data
|
||||
android:host="unionleitor.top"
|
||||
android:pathPattern="/pagina-manga/..*"
|
||||
android:scheme="https" />
|
||||
<data
|
||||
android:host="unionmangas.top"
|
||||
android:pathPattern="/perfil-manga/..*"
|
||||
android:scheme="http" />
|
||||
<data
|
||||
android:host="unionmangas.top"
|
||||
android:pathPattern="/pagina-manga/..*"
|
||||
android:scheme="http" />
|
||||
<data
|
||||
android:host="unionmangas.top"
|
||||
android:pathPattern="/perfil-manga/..*"
|
||||
android:scheme="https" />
|
||||
<data
|
||||
android:host="unionmangas.top"
|
||||
android:pathPattern="/pagina-manga/..*"
|
||||
android:scheme="https" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</application>
|
||||
</manifest>
|
|
@ -1,16 +0,0 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
ext {
|
||||
extName = 'Union Mangás'
|
||||
pkgNameSuffix = 'pt.unionmangas'
|
||||
extClass = '.UnionMangas'
|
||||
extVersionCode = 22
|
||||
libVersion = '1.2'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':lib-ratelimit')
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
Before Width: | Height: | Size: 3.0 KiB |
Before Width: | Height: | Size: 1.7 KiB |
Before Width: | Height: | Size: 3.8 KiB |
Before Width: | Height: | Size: 6.8 KiB |
Before Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 48 KiB |
|
@ -1,278 +0,0 @@
|
|||
package eu.kanade.tachiyomi.extension.pt.unionmangas
|
||||
|
||||
import com.github.salomonbrys.kotson.array
|
||||
import com.github.salomonbrys.kotson.nullObj
|
||||
import com.github.salomonbrys.kotson.obj
|
||||
import com.github.salomonbrys.kotson.string
|
||||
import com.google.gson.JsonElement
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonParser
|
||||
import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
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 okhttp3.FormBody
|
||||
import okhttp3.Headers
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import java.text.ParseException
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class UnionMangas : ParsedHttpSource() {
|
||||
|
||||
// Hardcode the id because the language wasn't specific.
|
||||
override val id: Long = 6931383302802153355
|
||||
|
||||
override val name = "Union Mangás"
|
||||
|
||||
override val baseUrl = "https://unionmangas.top"
|
||||
|
||||
override val lang = "pt-BR"
|
||||
|
||||
override val supportsLatest = true
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(3, TimeUnit.MINUTES)
|
||||
.readTimeout(3, TimeUnit.MINUTES)
|
||||
.writeTimeout(3, TimeUnit.MINUTES)
|
||||
.addInterceptor(RateLimitInterceptor(1, 2, TimeUnit.SECONDS))
|
||||
.build()
|
||||
|
||||
override fun headersBuilder(): Headers.Builder = Headers.Builder()
|
||||
.add("Accept", ACCEPT)
|
||||
.add("Accept-Language", ACCEPT_LANGUAGE)
|
||||
.add("Referer", "$baseUrl/home")
|
||||
|
||||
override fun popularMangaRequest(page: Int): Request {
|
||||
val listPath = if (page == 1) "" else "/visualizacoes/${page - 1}"
|
||||
val newHeaders = headersBuilder()
|
||||
.set("Referer", "$baseUrl/lista-mangas$listPath")
|
||||
.build()
|
||||
|
||||
val pageStr = if (page != 1) "/$page" else ""
|
||||
return GET("$baseUrl/lista-mangas/visualizacoes$pageStr", newHeaders)
|
||||
}
|
||||
|
||||
override fun popularMangaParse(response: Response): MangasPage {
|
||||
val results = super.popularMangaParse(response)
|
||||
|
||||
if (results.mangas.isEmpty()) {
|
||||
throw Exception(BLOCK_MESSAGE)
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
override fun popularMangaSelector(): String = "div.col-md-3.col-xs-6:has(img.img-thumbnail)"
|
||||
|
||||
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||
title = element.select("div[id^=bloco-tooltip] > b").first().text().withoutLanguage()
|
||||
thumbnail_url = element.select("a img").first()?.attr("src")
|
||||
setUrlWithoutDomain(element.select("a").last().attr("href"))
|
||||
}
|
||||
|
||||
override fun popularMangaNextPageSelector() = ".pagination li:contains(Next)"
|
||||
|
||||
override fun latestUpdatesRequest(page: Int): Request {
|
||||
val form = FormBody.Builder()
|
||||
.add("pagina", page.toString())
|
||||
.build()
|
||||
|
||||
val newHeaders = headersBuilder()
|
||||
.add("Content-Type", form.contentType().toString())
|
||||
.add("Content-Length", form.contentLength().toString())
|
||||
.add("Origin", baseUrl)
|
||||
.add("X-Requested-With", "XMLHttpRequest")
|
||||
.set("Accept", "*/*")
|
||||
.build()
|
||||
|
||||
return POST("$baseUrl/assets/noticias.php", newHeaders, form)
|
||||
}
|
||||
|
||||
override fun latestUpdatesParse(response: Response): MangasPage {
|
||||
val results = super.latestUpdatesParse(response)
|
||||
|
||||
if (results.mangas.isEmpty()) {
|
||||
throw Exception(BLOCK_MESSAGE)
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
override fun latestUpdatesSelector() = "div.row[style] div.col-md-12[style]"
|
||||
|
||||
override fun latestUpdatesFromElement(element: Element): SManga = SManga.create().apply {
|
||||
val infoElement = element.select("a.link-titulo")
|
||||
|
||||
title = infoElement.last().text().withoutLanguage()
|
||||
thumbnail_url = infoElement.first()?.select("img")?.attr("src")
|
||||
setUrlWithoutDomain(infoElement.last().attr("href"))
|
||||
}
|
||||
|
||||
override fun latestUpdatesNextPageSelector() = "div#linha-botao-mais"
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
if (query.startsWith(PREFIX_SLUG_SEARCH)) {
|
||||
val slug = query.removePrefix(PREFIX_SLUG_SEARCH)
|
||||
return GET("$baseUrl/pagina-manga/$slug", headers)
|
||||
}
|
||||
|
||||
val newHeaders = headersBuilder()
|
||||
.set("Accept", ACCEPT_JSON)
|
||||
.add("X-Requested-With", "XMLHttpRequest")
|
||||
.build()
|
||||
|
||||
val url = "$baseUrl/assets/busca.php".toHttpUrlOrNull()!!.newBuilder()
|
||||
.addQueryParameter("titulo", query)
|
||||
|
||||
return GET(url.toString(), newHeaders)
|
||||
}
|
||||
|
||||
override fun searchMangaParse(response: Response): MangasPage {
|
||||
val requestUrl = response.request.url.toString()
|
||||
|
||||
if (requestUrl.contains("pagina-manga")) {
|
||||
val slug = requestUrl.substringAfter("pagina-manga/")
|
||||
val manga = mangaDetailsParse(response)
|
||||
.apply { url = "/pagina-manga/$slug" }
|
||||
return MangasPage(listOf(manga), false)
|
||||
}
|
||||
|
||||
val result = response.asJson().nullObj
|
||||
?: throw Exception(BLOCK_MESSAGE)
|
||||
|
||||
val mangas = result["items"].array
|
||||
.map { searchMangaFromObject(it.obj) }
|
||||
|
||||
return MangasPage(mangas, false)
|
||||
}
|
||||
|
||||
private fun searchMangaFromObject(obj: JsonObject): SManga = SManga.create().apply {
|
||||
title = obj["titulo"].string.withoutLanguage()
|
||||
thumbnail_url = obj["imagem"].string
|
||||
setUrlWithoutDomain("$baseUrl/pagina-manga/${obj["url"].string}")
|
||||
}
|
||||
|
||||
override fun mangaDetailsRequest(manga: SManga): Request {
|
||||
// Map the mangas that are already in library with the old URL to the new one.
|
||||
val newUrl = manga.url.replace("perfil-manga", "pagina-manga")
|
||||
return GET(baseUrl + newUrl, headers)
|
||||
}
|
||||
|
||||
override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
|
||||
val infoElement = document.select("div.perfil-manga").firstOrNull()
|
||||
?: throw Exception(BLOCK_MESSAGE)
|
||||
val rowInfo = infoElement.select("div.row:eq(2)").first()
|
||||
|
||||
title = infoElement.select("h2").first().text().withoutLanguage()
|
||||
author = rowInfo.select("div.col-md-8:eq(4)").first().textWithoutLabel()
|
||||
artist = rowInfo.select("div.col-md-8:eq(5)").first().textWithoutLabel()
|
||||
genre = rowInfo.select("div.col-md-8:eq(3)").first().textWithoutLabel()
|
||||
status = rowInfo.select("div.col-md-8:eq(6)").first().text().toStatus()
|
||||
description = rowInfo.select("div.col-md-8:eq(8)").first().text()
|
||||
thumbnail_url = infoElement.select(".img-thumbnail").first().attr("src")
|
||||
}
|
||||
|
||||
override fun chapterListParse(response: Response): List<SChapter> {
|
||||
val results = super.chapterListParse(response)
|
||||
|
||||
if (results.isEmpty()) {
|
||||
throw Exception(BLOCK_MESSAGE)
|
||||
}
|
||||
|
||||
return results
|
||||
}
|
||||
|
||||
override fun chapterListSelector() = "div.row.capitulos"
|
||||
|
||||
override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
|
||||
val firstColumn = element.select("div.col-md-6:eq(0)").first()!!
|
||||
val secondColumn = element.select("div.col-md-6:eq(1)").firstOrNull()
|
||||
|
||||
name = firstColumn.select("a").first().text()
|
||||
scanlator = secondColumn?.select("a")?.joinToString { it.text() }
|
||||
date_upload = firstColumn.select("span").last()!!.text().toDate()
|
||||
|
||||
// For some reason, setUrlWithoutDomain does not work when the url have spaces.
|
||||
val absoluteUrlFixed = firstColumn.select("a").first()
|
||||
.attr("href")
|
||||
.replace(" ", "%20")
|
||||
setUrlWithoutDomain(absoluteUrlFixed)
|
||||
}
|
||||
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
return document.select("img.img-responsive.img-manga")
|
||||
.filter { it.attr("src").contains("/leitor/") }
|
||||
.mapIndexed { i, element ->
|
||||
Page(i, document.location(), element.absUrl("src"))
|
||||
}
|
||||
}
|
||||
|
||||
override fun imageUrlParse(document: Document) = ""
|
||||
|
||||
override fun imageRequest(page: Page): Request {
|
||||
val newHeaders = headersBuilder()
|
||||
.set("Accept", ACCEPT_IMAGE)
|
||||
.set("Referer", page.url)
|
||||
.build()
|
||||
|
||||
return GET(page.imageUrl!!, newHeaders)
|
||||
}
|
||||
|
||||
override fun searchMangaSelector() = throw Exception("This method should not be called!")
|
||||
|
||||
override fun searchMangaFromElement(element: Element): SManga = throw Exception("This method should not be called!")
|
||||
|
||||
override fun searchMangaNextPageSelector() = throw Exception("This method should not be called!")
|
||||
|
||||
private fun String.toDate(): Long {
|
||||
return try {
|
||||
DATE_FORMATTER.parse(this)?.time ?: 0L
|
||||
} catch (e: ParseException) {
|
||||
0L
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.toStatus(): Int = when {
|
||||
contains("Ativo") -> SManga.ONGOING
|
||||
contains("Completo") -> SManga.COMPLETED
|
||||
else -> SManga.UNKNOWN
|
||||
}
|
||||
|
||||
private fun String.withoutLanguage(): String =
|
||||
replace("(pt-br)", "", true).trim()
|
||||
|
||||
private fun Element.textWithoutLabel(): String = text()!!.substringAfter(":").trim()
|
||||
|
||||
private fun Response.asJson(): JsonElement = JsonParser.parseString(body!!.string())
|
||||
|
||||
companion object {
|
||||
private const val ACCEPT = "text/html,application/xhtml+xml,application/xml;q=0.9," +
|
||||
"image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"
|
||||
private const val ACCEPT_IMAGE = "image/avif,image/webp,image/apng,image/svg+xml,image/*,*/*;q=0.8"
|
||||
private const val ACCEPT_JSON = "application/json, text/javascript, */*; q=0.01"
|
||||
private const val ACCEPT_LANGUAGE = "pt-BR,pt;q=0.9,en-US;q=0.8,en;q=0.7,es;q=0.6,gl;q=0.5"
|
||||
private const val USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
|
||||
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36"
|
||||
|
||||
private const val BLOCK_MESSAGE = "O site está bloqueando o Tachiyomi. " +
|
||||
"Migre para outra fonte caso o problema persistir."
|
||||
|
||||
private val DATE_FORMATTER by lazy {
|
||||
SimpleDateFormat("(dd/MM/yyyy)", Locale.ENGLISH)
|
||||
}
|
||||
|
||||
const val PREFIX_SLUG_SEARCH = "slug:"
|
||||
}
|
||||
}
|
|
@ -1,38 +0,0 @@
|
|||
package eu.kanade.tachiyomi.extension.pt.unionmangas
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Intent
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
/**
|
||||
* Springboard that accepts https://unionleitor.top/perfil-manga/xxxxxx intents
|
||||
* and redirects them to the main Tachiyomi process.
|
||||
*/
|
||||
class UnionMangasUrlActivity : Activity() {
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
val pathSegments = intent?.data?.pathSegments
|
||||
if (pathSegments != null && pathSegments.size > 1) {
|
||||
val slug = pathSegments[1]
|
||||
val mainIntent = Intent().apply {
|
||||
action = "eu.kanade.tachiyomi.SEARCH"
|
||||
putExtra("query", "${UnionMangas.PREFIX_SLUG_SEARCH}$slug")
|
||||
putExtra("filter", packageName)
|
||||
}
|
||||
|
||||
try {
|
||||
startActivity(mainIntent)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
Log.e("UnionMangasUrl", e.toString())
|
||||
}
|
||||
} else {
|
||||
Log.e("UnionMangasUrl", "could not parse uri from intent $intent")
|
||||
}
|
||||
|
||||
finish()
|
||||
exitProcess(0)
|
||||
}
|
||||
}
|
|
@ -1,2 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest package="eu.kanade.tachiyomi.extension" />
|
|
@ -1,16 +0,0 @@
|
|||
apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
ext {
|
||||
extName = 'YES Mangás'
|
||||
pkgNameSuffix = 'pt.yesmangas'
|
||||
extClass = '.YesMangas'
|
||||
extVersionCode = 7
|
||||
libVersion = '1.2'
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation project(':lib-ratelimit')
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
Before Width: | Height: | Size: 3.7 KiB |
Before Width: | Height: | Size: 2.0 KiB |
Before Width: | Height: | Size: 4.9 KiB |
Before Width: | Height: | Size: 8.3 KiB |
Before Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 50 KiB |
|
@ -1,146 +0,0 @@
|
|||
package eu.kanade.tachiyomi.extension.pt.yesmangas
|
||||
|
||||
import eu.kanade.tachiyomi.lib.ratelimit.RateLimitInterceptor
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.source.model.FilterList
|
||||
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 okhttp3.Headers
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import org.jsoup.select.Elements
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class YesMangas : ParsedHttpSource() {
|
||||
|
||||
// Hardcode the id because the language wasn't specific.
|
||||
override val id: Long = 7187189302580957274
|
||||
|
||||
override val name = "YES Mangás"
|
||||
|
||||
override val baseUrl = "https://yesmangas1.com"
|
||||
|
||||
override val lang = "pt-BR"
|
||||
|
||||
override val supportsLatest = true
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.addInterceptor(RateLimitInterceptor(1, 1, TimeUnit.SECONDS))
|
||||
.build()
|
||||
|
||||
override fun headersBuilder(): Headers.Builder = Headers.Builder()
|
||||
.add("User-Agent", USER_AGENT)
|
||||
.add("Origin", baseUrl)
|
||||
.add("Referer", baseUrl)
|
||||
|
||||
override fun popularMangaRequest(page: Int): Request = GET(baseUrl, headers)
|
||||
|
||||
override fun popularMangaSelector(): String = "div#destaques div.three.columns a.img"
|
||||
|
||||
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||
title = element.attr("title").withoutLanguage()
|
||||
thumbnail_url = element.select("img").attr("data-path").toLargeUrl()
|
||||
url = element.attr("href")
|
||||
}
|
||||
|
||||
override fun popularMangaNextPageSelector(): String? = null
|
||||
|
||||
override fun latestUpdatesRequest(page: Int): Request = GET(baseUrl, headers)
|
||||
|
||||
override fun latestUpdatesSelector(): String = "div#lancamentos table.u-full-width tbody tr td:eq(0) a"
|
||||
|
||||
override fun latestUpdatesFromElement(element: Element): SManga = SManga.create().apply {
|
||||
title = element.attr("title").withoutLanguage()
|
||||
thumbnail_url = element.select("img").attr("data-path").toLargeUrl()
|
||||
setUrlWithoutDomain(element.attr("href"))
|
||||
}
|
||||
|
||||
override fun latestUpdatesNextPageSelector(): String? = null
|
||||
|
||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||
val url = "$baseUrl/search".toHttpUrlOrNull()!!.newBuilder()
|
||||
.addQueryParameter("q", query)
|
||||
|
||||
return GET(url.toString(), headers)
|
||||
}
|
||||
|
||||
override fun searchMangaSelector(): String = "tbody#leituras tr td:eq(0) a"
|
||||
|
||||
override fun searchMangaFromElement(element: Element): SManga = SManga.create().apply {
|
||||
title = element.attr("title").withoutLanguage()
|
||||
thumbnail_url = element.select("img").attr("data-path").toLargeUrl()
|
||||
setUrlWithoutDomain(element.attr("href"))
|
||||
}
|
||||
|
||||
override fun searchMangaNextPageSelector(): String? = null
|
||||
|
||||
override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
|
||||
val container = document.select("div#descricao").first()
|
||||
|
||||
author = container.select("ul li:contains(Autor)").textWithoutLabel()
|
||||
artist = container.select("ul li:contains(Desenho)").textWithoutLabel()
|
||||
genre = container.select("ul li:contains(Categorias)").textWithoutLabel()
|
||||
status = container.select("ul li:contains(Status)").text().toStatus()
|
||||
description = container.select("article").text()
|
||||
.substringBefore("Relacionados")
|
||||
thumbnail_url = container.select("img").first()
|
||||
.attr("data-path")
|
||||
.toLargeUrl()
|
||||
}
|
||||
|
||||
override fun chapterListSelector(): String = "div#capitulos a.button"
|
||||
|
||||
override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
|
||||
name = element.attr("title").substringAfter(" - ")
|
||||
chapter_number = element.text().toFloatOrNull() ?: -1f
|
||||
setUrlWithoutDomain(element.attr("href"))
|
||||
}
|
||||
|
||||
override fun pageListRequest(chapter: SChapter): Request {
|
||||
val newHeaders = headersBuilder()
|
||||
.set("Referer", baseUrl + chapter.url.substringBeforeLast("/"))
|
||||
.build()
|
||||
|
||||
return GET(baseUrl + chapter.url, newHeaders)
|
||||
}
|
||||
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
return document.select("div.read-slideshow a img")
|
||||
.mapIndexed { i, el -> Page(i, document.location(), el.attr("src")) }
|
||||
}
|
||||
|
||||
override fun imageUrlParse(document: Document): String = ""
|
||||
|
||||
override fun imageRequest(page: Page): Request {
|
||||
val newHeaders = headersBuilder()
|
||||
.set("Referer", page.url)
|
||||
.build()
|
||||
|
||||
return GET(page.imageUrl!!, newHeaders)
|
||||
}
|
||||
|
||||
private fun String.withoutLanguage(): String = replace(LANG_REGEX, "")
|
||||
|
||||
private fun String.toLargeUrl(): String = replace(IMAGE_REGEX, "_full.")
|
||||
|
||||
private fun Elements.textWithoutLabel(): String = text()!!.substringAfter(":").trim()
|
||||
|
||||
private fun String.toStatus() = when {
|
||||
contains("Completo") -> SManga.COMPLETED
|
||||
contains("Ativo") -> SManga.ONGOING
|
||||
else -> SManga.UNKNOWN
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val USER_AGENT = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " +
|
||||
"AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.128 Safari/537.36"
|
||||
|
||||
private val LANG_REGEX = "( )?\\((PT-)?BR\\)".toRegex()
|
||||
private val IMAGE_REGEX = "_(small|medium|xmedium|xlarge)\\.".toRegex()
|
||||
}
|
||||
}
|