Remove two dead Brazilian sources (#18754)

Remove two dead Brazilian sources.
This commit is contained in:
Alessandro Jean 2023-10-27 12:03:02 -03:00 committed by GitHub
parent 83719416e8
commit 63277bab65
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 0 additions and 761 deletions

View File

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest />

View File

@ -1,17 +0,0 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext {
extName = 'Golden Mangás'
pkgNameSuffix = 'pt.goldenmangas'
extClass = '.GoldenMangas'
extVersionCode = 22
isNsfw = true
}
dependencies {
implementation(project(":lib-randomua"))
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 72 KiB

View File

@ -1,333 +0,0 @@
package eu.kanade.tachiyomi.extension.pt.goldenmangas
import android.app.Application
import android.content.SharedPreferences
import android.widget.Toast
import androidx.preference.EditTextPreference
import androidx.preference.ListPreference
import androidx.preference.PreferenceScreen
import eu.kanade.tachiyomi.lib.randomua.PREF_KEY_CUSTOM_UA
import eu.kanade.tachiyomi.lib.randomua.PREF_KEY_RANDOM_UA
import eu.kanade.tachiyomi.lib.randomua.RANDOM_UA_ENTRIES
import eu.kanade.tachiyomi.lib.randomua.getPrefCustomUA
import eu.kanade.tachiyomi.lib.randomua.getPrefUAType
import eu.kanade.tachiyomi.lib.randomua.setRandomUserAgent
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.source.ConfigurableSource
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
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import uy.kohesive.injekt.Injekt
import uy.kohesive.injekt.api.get
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
import kotlin.time.Duration.Companion.seconds
class GoldenMangas : ParsedHttpSource(), ConfigurableSource {
// Hardcode the id because the language wasn't specific.
override val id: Long = 6858719406079923084
override val name = "Golden Mangás"
override val baseUrl = "https://www.goldenmanga.top"
override val lang = "pt-BR"
override val supportsLatest = true
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
private val baseHttpUrl: HttpUrl
get() = preferences.baseUrl.toHttpUrl()
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
.connectTimeout(1, TimeUnit.MINUTES)
.readTimeout(1, TimeUnit.MINUTES)
.writeTimeout(1, TimeUnit.MINUTES)
.addInterceptor(ObsoleteExtensionInterceptor())
.setRandomUserAgent(
userAgentType = preferences.getPrefUAType(),
customUA = preferences.getPrefCustomUA(),
)
.rateLimitPath("/mangas", 1, 8.seconds)
.rateLimitPath("/mm-admin/uploads", 1, 8.seconds)
.rateLimitPath("/timthumb.php", 1, 3.seconds)
.rateLimitPath("/index.php", 1, 3.seconds)
.addInterceptor(::guessNewUrlIntercept)
.build()
override fun headersBuilder(): Headers.Builder = Headers.Builder()
.add("Accept", ACCEPT)
.add("Accept-Language", ACCEPT_LANGUAGE)
.add("Referer", REFERER)
override fun popularMangaRequest(page: Int): Request = GET(baseUrl, headers)
override fun popularMangaSelector(): String = "div#maisLidos div.itemmanga:not(:contains(Avisos e Recados))"
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
title = element.selectFirst("h3")!!.text().withoutLanguage()
thumbnail_url = element.selectFirst("img")!!.absUrl("src")
url = element.attr("href")
}
override fun popularMangaNextPageSelector(): String? = null
override fun latestUpdatesRequest(page: Int): Request {
val path = if (page > 1) "/index.php?pagina=$page" else ""
return GET("$baseUrl$path", headers)
}
override fun latestUpdatesSelector() = "div.col-sm-12.atualizacao > div.row:not(:contains(Avisos e Recados))"
override fun latestUpdatesFromElement(element: Element): SManga = SManga.create().apply {
val infoElement = element.selectFirst("div.col-sm-10.col-xs-8 h3")!!
val thumbElement = element.selectFirst("a:first-child div img")!!
title = infoElement.text().withoutLanguage()
thumbnail_url = thumbElement.absUrl("src")
.replace("w=100&h=140", "w=380&h=600")
url = element.select("a:first-child").attr("href")
}
override fun latestUpdatesNextPageSelector() = "ul.pagination li:last-child a"
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val newHeaders = headers.newBuilder()
.set("Referer", "$baseUrl/mangas")
.build()
val url = "$baseUrl/mangas".toHttpUrl().newBuilder()
.addQueryParameter("busca", query)
.toString()
return GET(url, newHeaders)
}
override fun searchMangaSelector() = "div.mangas.col-lg-2 a"
override fun searchMangaFromElement(element: Element): SManga = SManga.create().apply {
title = element.selectFirst("h3")!!.text().withoutLanguage()
thumbnail_url = element.selectFirst("img")!!.absUrl("src")
url = element.attr("href")
}
override fun searchMangaNextPageSelector(): String? = null
override fun mangaDetailsParse(response: Response): SManga {
val mangaResult = runCatching { super.mangaDetailsParse(response) }
val manga = mangaResult.getOrNull()
if (manga?.title.isNullOrEmpty() && !response.hasChangedDomain) {
throw Exception(MIGRATE_WARNING)
}
return manga!!
}
override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
val infoElement = document.selectFirst("div.row > div.col-sm-8 > div.row")!!
val firstColumn = infoElement.selectFirst("div.col-sm-4.text-right > img")!!
val secondColumn = infoElement.selectFirst("div.col-sm-8")!!
title = secondColumn.select("h2:eq(0)").text().withoutLanguage()
author = secondColumn.select("h5:contains(Autor)").text().withoutLabel()
artist = secondColumn.select("h5:contains(Artista)").text().withoutLabel()
genre = secondColumn.select("h5:contains(Genero) a").toList()
.filter { it.text().isNotEmpty() }
.joinToString { it.text() }
status = secondColumn.select("h5:contains(Status) a").text().toStatus()
description = document.select("#manga_capitulo_descricao").text()
thumbnail_url = firstColumn.attr("abs:src")
}
override fun chapterListParse(response: Response): List<SChapter> {
val chaptersResult = runCatching { super.chapterListParse(response) }
val chapterList = chaptersResult.getOrNull()
if (chapterList.isNullOrEmpty() && !response.hasChangedDomain) {
throw Exception(MIGRATE_WARNING)
}
return chapterList.orEmpty()
}
override fun chapterListSelector() = "ul#capitulos li.row"
override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
val firstColumn = element.selectFirst("a > div.col-sm-5")!!
val secondColumn = element.select("div.col-sm-5.text-right a:not([href^='/'])")
name = firstColumn.text().substringBefore("(").trim()
scanlator = secondColumn.joinToString { it.text() }
date_upload = firstColumn.select("div.col-sm-5 span[style]").text().toDate()
url = element.select("a").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(response: Response): List<Page> {
val pagesResult = runCatching { super.pageListParse(response) }
val pageList = pagesResult.getOrNull()
if (pageList.isNullOrEmpty() && !response.hasChangedDomain) {
throw Exception(MIGRATE_WARNING)
}
return pageList.orEmpty()
}
override fun pageListParse(document: Document): List<Page> {
val chapterImages = document.selectFirst("div.col-sm-12[id^='capitulos_images']:has(img[pag])")
val isNovel = document.selectFirst(".block_text_border") !== null
if (chapterImages == null && isNovel) {
throw Exception(CHAPTER_IS_NOVEL_ERROR)
}
return chapterImages?.select("img[pag]")
.orEmpty()
.mapIndexed { i, element ->
Page(i, document.location(), element.attr("abs: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 setupPreferenceScreen(screen: PreferenceScreen) {
val uaPreference = ListPreference(screen.context).apply {
key = PREF_KEY_RANDOM_UA
title = "User Agent aleatório"
summary = "%s"
entries = arrayOf("Desativado", "Desktop", "Celular")
entryValues = RANDOM_UA_ENTRIES
setDefaultValue("off")
setOnPreferenceChangeListener { _, _ ->
Toast.makeText(screen.context, RESTART_APP_MESSAGE, Toast.LENGTH_SHORT).show()
true
}
}
val customUaPreference = EditTextPreference(screen.context).apply {
key = PREF_KEY_CUSTOM_UA
title = "User Agent personalizado"
summary = "Deixe em branco para usar o User Agent padrão do aplicativo. " +
"Ignorado se User Agent aleatório está ativado."
setOnPreferenceChangeListener { _, newValue ->
try {
Headers.Builder().add("User-Agent", newValue as String).build()
Toast.makeText(screen.context, RESTART_APP_MESSAGE, Toast.LENGTH_SHORT).show()
true
} catch (e: IllegalArgumentException) {
Toast.makeText(screen.context, "User Agent inválido: ${e.message}", Toast.LENGTH_LONG).show()
false
}
}
}
screen.addPreference(uaPreference)
screen.addPreference(customUaPreference)
}
private fun guessNewUrlIntercept(chain: Interceptor.Chain): Response {
val response = chain.proceed(chain.request())
if (chain.request().url.host == "raw.githubusercontent.com") {
return response
}
if (response.hasChangedDomain && preferences.baseUrl == baseUrl) {
return response
}
preferences.baseUrl = "https://${response.request.url.host}"
val newUrl = chain.request().url.toString()
.replaceFirst(baseUrl, preferences.baseUrl)
.toHttpUrl()
val newRequest = chain.request().newBuilder()
.url(newUrl)
.build()
response.close()
return chain.proceed(newRequest)
}
private var SharedPreferences.baseUrl: String
get() = getString(BASE_URL_PREF, this@GoldenMangas.baseUrl)!!
set(newValue) = edit().putString(BASE_URL_PREF, newValue).apply()
private fun String.toDate(): Long {
return runCatching { DATE_FORMATTER.parse(trim())?.time }
.getOrNull() ?: 0L
}
private val Response.hasChangedDomain: Boolean
get() = request.url.host != baseHttpUrl.host &&
request.url.host.contains("goldenmang")
private fun String.toStatus() = when (this) {
"Ativo" -> SManga.ONGOING
"Completo" -> SManga.COMPLETED
else -> SManga.UNKNOWN
}
private fun String.withoutLabel(): String = substringAfter(":").trim()
private fun String.withoutLanguage(): String = replace(FLAG_REGEX, "").trim()
companion object {
private const val ACCEPT = "text/html,application/xhtml+xml,application/xml;q=0.9," +
"image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"
private const val ACCEPT_IMAGE = "image/webp,image/apng,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 REFERER = "https://google.com/"
private val FLAG_REGEX = "\\((Pt[-/]br|Scan)\\)".toRegex(RegexOption.IGNORE_CASE)
private const val CHAPTER_IS_NOVEL_ERROR =
"O capítulo é uma novel em formato de texto e não possui imagens."
private const val MIGRATE_WARNING = "Migre o item da Golden Mangás para Golden Mangás para atualizar a URL."
private val DATE_FORMATTER by lazy {
SimpleDateFormat("(dd/MM/yyyy)", Locale("pt", "BR"))
}
private const val RESTART_APP_MESSAGE = "Reinicie o aplicativo para aplicar as alterações."
private const val BASE_URL_PREF = "base_url"
}
}

View File

@ -1,43 +0,0 @@
package eu.kanade.tachiyomi.extension.pt.goldenmangas
import eu.kanade.tachiyomi.network.GET
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import okhttp3.Interceptor
import okhttp3.Response
import uy.kohesive.injekt.injectLazy
import java.io.IOException
class ObsoleteExtensionInterceptor : Interceptor {
private val json: Json by injectLazy()
private var isObsolete: Boolean? = null
override fun intercept(chain: Interceptor.Chain): Response {
if (isObsolete == null) {
val extRepoResponse = chain.proceed(GET(REPO_URL))
val extRepo = json.decodeFromString<List<ExtensionJsonObject>>(extRepoResponse.body.string())
isObsolete = !extRepo.any { ext ->
ext.pkg == this.javaClass.`package`?.name && ext.lang == "pt-BR"
}
}
if (isObsolete == true) {
throw IOException("Extensão obsoleta. Desinstale e migre para outras fontes.")
}
return chain.proceed(chain.request())
}
@Serializable
private data class ExtensionJsonObject(
val pkg: String,
val lang: String,
)
companion object {
private const val REPO_URL = "https://raw.githubusercontent.com/tachiyomiorg/tachiyomi-extensions/repo/index.min.json"
}
}

View File

@ -1,90 +0,0 @@
package eu.kanade.tachiyomi.extension.pt.goldenmangas
import android.os.SystemClock
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Response
import java.io.IOException
import java.util.ArrayDeque
import java.util.concurrent.Semaphore
import kotlin.time.Duration
import kotlin.time.Duration.Companion.seconds
@Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN")
class SpecificPathRateLimitInterceptor(
private val path: String,
private val permits: Int,
period: Duration,
) : Interceptor {
private val requestQueue = ArrayDeque<Long>(permits)
private val rateLimitMillis = period.inWholeMilliseconds
private val fairLock = Semaphore(1, true)
override fun intercept(chain: Interceptor.Chain): Response {
val call = chain.call()
if (call.isCanceled()) throw IOException("Canceled")
val request = chain.request()
if (!request.url.encodedPath.startsWith(path)) {
return chain.proceed(request)
}
try {
fairLock.acquire()
} catch (e: InterruptedException) {
throw IOException(e)
}
val requestQueue = this.requestQueue
val timestamp: Long
try {
synchronized(requestQueue) {
while (requestQueue.size >= permits) { // queue is full, remove expired entries
val periodStart = SystemClock.elapsedRealtime() - rateLimitMillis
var hasRemovedExpired = false
while (requestQueue.isEmpty().not() && requestQueue.first <= periodStart) {
requestQueue.removeFirst()
hasRemovedExpired = true
}
if (call.isCanceled()) {
throw IOException("Canceled")
} else if (hasRemovedExpired) {
break
} else {
try { // wait for the first entry to expire, or notified by cached response
(requestQueue as Object).wait(requestQueue.first - periodStart)
} catch (_: InterruptedException) {
continue
}
}
}
// add request to queue
timestamp = SystemClock.elapsedRealtime()
requestQueue.addLast(timestamp)
}
} finally {
fairLock.release()
}
val response = chain.proceed(request)
if (response.networkResponse == null) { // response is cached, remove it from queue
synchronized(requestQueue) {
if (requestQueue.isEmpty() || timestamp < requestQueue.first) return@synchronized
requestQueue.removeFirstOccurrence(timestamp)
(requestQueue as Object).notifyAll()
}
}
return response
}
}
fun OkHttpClient.Builder.rateLimitPath(
path: String,
permits: Int,
period: Duration = 1.seconds,
) = addInterceptor(SpecificPathRateLimitInterceptor(path, permits, period))

View File

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest />

View File

@ -1,13 +0,0 @@
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlinx-serialization'
ext {
extName = 'Mundo Webtoon'
pkgNameSuffix = 'pt.mundowebtoon'
extClass = '.MundoWebtoon'
extVersionCode = 8
isNsfw = true
}
apply from: "$rootDir/common.gradle"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

View File

@ -1,218 +0,0 @@
package eu.kanade.tachiyomi.extension.pt.mundowebtoon
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.interceptor.rateLimit
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.FormBody
import okhttp3.Headers
import okhttp3.HttpUrl.Companion.toHttpUrl
import okhttp3.Interceptor
import okhttp3.MediaType.Companion.toMediaType
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import okhttp3.ResponseBody.Companion.toResponseBody
import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import org.jsoup.select.Elements
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
class MundoWebtoon : ParsedHttpSource() {
override val name = "Mundo Webtoon"
override val baseUrl = "https://mundowebtoon.com"
override val lang = "pt-BR"
override val supportsLatest = true
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
.addInterceptor(ObsoleteExtensionInterceptor())
.addInterceptor(::sanitizeHtmlIntercept)
.rateLimit(1, 3, TimeUnit.SECONDS)
.build()
override fun headersBuilder(): Headers.Builder = Headers.Builder()
.add("Accept", ACCEPT)
.add("Accept-Language", ACCEPT_LANGUAGE)
.add("Referer", "$baseUrl/")
override fun popularMangaRequest(page: Int): Request = GET(baseUrl, headers)
override fun popularMangaSelector(): String =
"div.section:contains(mais lídos) + div.section div.andro_product"
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
title = element.select("h6.andro_product-title small").text().withoutLanguage()
thumbnail_url = element.select("div.andro_product-thumb img").srcAttr()
setUrlWithoutDomain(element.select("div.andro_product-thumb > a").attr("abs:href"))
}
override fun popularMangaNextPageSelector(): String? = null
override fun latestUpdatesRequest(page: Int): Request {
val path = if (page > 1) "/index.php?pagina=$page" else ""
return GET("$baseUrl$path", headers)
}
override fun latestUpdatesSelector() = "div.row.atualizacoes div.andro_product"
override fun latestUpdatesFromElement(element: Element): SManga = SManga.create().apply {
title = element.select("h5.andro_product-title").text().withoutLanguage()
thumbnail_url = element.select("div.andro_product-thumb img").srcAttr()
setUrlWithoutDomain(element.select("div.andro_product-thumb > a").attr("abs:href"))
}
override fun latestUpdatesNextPageSelector() = "ul.paginacao li:last-child:not(.active) a"
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
val newHeaders = headers.newBuilder()
.set("Referer", "$baseUrl/mangas")
.build()
val url = "$baseUrl/mangas".toHttpUrl().newBuilder()
.addQueryParameter("busca", query)
.toString()
return GET(url, newHeaders)
}
override fun searchMangaSelector() = "div.container div.andro_product"
override fun searchMangaFromElement(element: Element): SManga = SManga.create().apply {
title = element.select("span.andro_product-title").text().withoutLanguage()
thumbnail_url = element.select("div.andro_product-thumb img").srcAttr()
setUrlWithoutDomain(element.select("div.andro_product-thumb > a").attr("abs:href"))
}
override fun searchMangaNextPageSelector(): String? = null
override fun mangaDetailsParse(document: Document): SManga = SManga.create().apply {
val infoElement = document.selectFirst("div.andro_product-single-content")!!
title = infoElement.select("div.mangaTitulo h3").text().withoutLanguage()
author = infoElement.select("div.BlDataItem a[href*=autor]")
.joinToString(", ") { it.text() }
artist = infoElement.select("div.BlDataItem a[href*=artista]")
.joinToString(", ") { it.text() }
genre = infoElement.select("div.col-md-12 a.label-warning[href*=genero]").toList()
.filter { it.text().isNotEmpty() }
.joinToString { it.text().trim() }
status = infoElement.selectFirst("div.BlDataItem a[href*=status]")
?.text()?.toStatus() ?: SManga.UNKNOWN
description = infoElement.select("div.andro_product-excerpt").text()
thumbnail_url = document.select("div.andro_product-single-thumb img").srcAttr()
}
override fun chapterListSelector() = "div.CapitulosListaTodos div.CapitulosListaItem"
override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
name = element.selectFirst("h5")!!.ownText()
scanlator = element.select("a.color_gray[target='_blank']")
.joinToString(", ") { it.text() }
date_upload = element.select("h5 span[style]").text().toDate()
setUrlWithoutDomain(element.selectFirst("a")!!.attr("abs:href"))
}
override fun pageListRequest(chapter: SChapter): Request {
val chapterUrl = (baseUrl + chapter.url).toHttpUrl()
val payload = FormBody.Builder()
.add("data", chapterUrl.pathSegments[1])
.add("num", chapterUrl.pathSegments[2])
.add("modo", "1")
.add("busca", "img")
.build()
val newHeaders = headersBuilder()
.add("Content-Length", payload.contentLength().toString())
.add("Content-Type", payload.contentType().toString())
.set("Referer", baseUrl + chapter.url)
.build()
return POST("$baseUrl/leitor_image.php", newHeaders, payload)
}
override fun pageListParse(document: Document): List<Page> {
return document.select("img[pag]")
.mapIndexed { i, element ->
Page(i, document.location(), element.attr("abs: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 sanitizeHtmlIntercept(chain: Interceptor.Chain): Response {
val response = chain.proceed(chain.request())
if (!response.headers["Content-Type"].orEmpty().contains("text/html")) {
return response
}
val newBody = response.body.string()
.replace("\t", "")
.replace(SCRIPT_REGEX, "")
.replace(HEAD_REGEX, "<head></head>")
.replace(COMMENT_REGEX, "")
.toResponseBody(HTML_MEDIA_TYPE)
response.close()
return response.newBuilder()
.body(newBody)
.build()
}
private fun Elements.srcAttr(): String =
attr(if (hasAttr("data-src")) "data-src" else "src")
private fun String.toDate(): Long {
return runCatching { DATE_FORMATTER.parse(trim())?. time }
.getOrNull() ?: 0L
}
private fun String.toStatus() = when (this) {
"Ativo" -> SManga.ONGOING
"Completo" -> SManga.COMPLETED
else -> SManga.UNKNOWN
}
private fun String.withoutLanguage(): String = replace(FLAG_REGEX, "").trim()
companion object {
private const val ACCEPT = "text/html,application/xhtml+xml,application/xml;q=0.9," +
"image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9"
private const val ACCEPT_IMAGE = "image/webp,image/apng,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 val FLAG_REGEX = "\\((Pt[-/]br|Scan)\\)".toRegex(RegexOption.IGNORE_CASE)
private val SCRIPT_REGEX = "<script>.*</script>"
.toRegex(setOf(RegexOption.IGNORE_CASE, RegexOption.MULTILINE))
private val HEAD_REGEX = "<head>.*</head>"
.toRegex(setOf(RegexOption.IGNORE_CASE, RegexOption.MULTILINE))
private val COMMENT_REGEX = "<!--.*-->".toRegex(RegexOption.MULTILINE)
private val HTML_MEDIA_TYPE = "text/html".toMediaType()
private val DATE_FORMATTER by lazy {
SimpleDateFormat("(dd/MM/yyyy)", Locale.ENGLISH)
}
}
}

View File

@ -1,43 +0,0 @@
package eu.kanade.tachiyomi.extension.pt.mundowebtoon
import eu.kanade.tachiyomi.network.GET
import kotlinx.serialization.Serializable
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import okhttp3.Interceptor
import okhttp3.Response
import uy.kohesive.injekt.injectLazy
import java.io.IOException
class ObsoleteExtensionInterceptor : Interceptor {
private val json: Json by injectLazy()
private var isObsolete: Boolean? = null
override fun intercept(chain: Interceptor.Chain): Response {
if (isObsolete == null) {
val extRepoResponse = chain.proceed(GET(REPO_URL))
val extRepo = json.decodeFromString<List<ExtensionJsonObject>>(extRepoResponse.body.string())
isObsolete = !extRepo.any { ext ->
ext.pkg == this.javaClass.`package`?.name && ext.lang == "pt-BR"
}
}
if (isObsolete == true) {
throw IOException("Extensão obsoleta. Desinstale e migre para outras fontes.")
}
return chain.proceed(chain.request())
}
@Serializable
private data class ExtensionJsonObject(
val pkg: String,
val lang: String,
)
companion object {
private const val REPO_URL = "https://raw.githubusercontent.com/tachiyomiorg/tachiyomi-extensions/repo/index.min.json"
}
}