Remove some sources that are in a cat and mouse game. (#7065)

This commit is contained in:
Alessandro Jean 2021-05-17 15:09:18 -03:00 committed by GitHub
parent cffc0157a6
commit 703ed0b63b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 0 additions and 1069 deletions

View File

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

View File

@ -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"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 98 KiB

View File

@ -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."
}
}

View File

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

View File

@ -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"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

View File

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

View File

@ -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>

View File

@ -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"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 48 KiB

View File

@ -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:"
}
}

View File

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

View File

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

View File

@ -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"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 50 KiB

View File

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