Fix LectorManga HTTP error 403, Add MangaMx genre filter and config screen (#6323)

* Fix LectorManga HTTP error 403

* Add genres filter, config +18 filter.

* Fix tachiyomiorg/tachiyomi-extensions#6325
This commit is contained in:
Edgar Mejía 2021-03-28 14:19:11 -06:00 committed by GitHub
parent 461228d7d7
commit 39ac1f81a6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 163 additions and 59 deletions

View File

@ -5,7 +5,7 @@ ext {
extName = 'LectorManga'
pkgNameSuffix = 'es.lectormanga'
extClass = '.LectorManga'
extVersionCode = 15
extVersionCode = 16
libVersion = '1.2'
}

View File

@ -17,6 +17,7 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import okhttp3.Headers
import okhttp3.HttpUrl
import okhttp3.OkHttpClient
import okhttp3.Request
@ -39,6 +40,15 @@ class LectorManga : ConfigurableSource, ParsedHttpSource() {
override val supportsLatest = true
private val userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 " +
"(KHTML, like Gecko) Chrome/80.0.3987.132 Safari/537.36"
override fun headersBuilder(): Headers.Builder {
return Headers.Builder()
.add("User-Agent", userAgent)
.add("Referer", "$baseUrl/")
}
private val imageCDNUrl = "https://img1.followmanga.com"
private val preferences: SharedPreferences by lazy {

View File

@ -5,7 +5,7 @@ ext {
extName = 'MangaMx'
pkgNameSuffix = 'es.mangamx'
extClass = '.MangaMx'
extVersionCode = 9
extVersionCode = 10
libVersion = '1.2'
}

View File

@ -1,6 +1,10 @@
package eu.kanade.tachiyomi.extension.es.mangamx
import android.app.Application
import android.content.SharedPreferences
import android.net.Uri
import android.support.v7.preference.CheckBoxPreference
import android.support.v7.preference.PreferenceScreen
import android.util.Base64
import com.github.salomonbrys.kotson.get
import com.github.salomonbrys.kotson.string
@ -8,6 +12,7 @@ import com.google.gson.JsonElement
import com.google.gson.JsonParser
import eu.kanade.tachiyomi.network.GET
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.source.ConfigurableSource
import eu.kanade.tachiyomi.source.model.Filter
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage
@ -21,29 +26,36 @@ 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.nio.charset.Charset
import java.text.SimpleDateFormat
import java.util.Locale
open class MangaMx : ParsedHttpSource() {
// Info
open class MangaMx : ConfigurableSource, ParsedHttpSource() {
override val name = "MangaMx"
override val baseUrl = "https://manga-mx.com"
override val lang = "es"
override val supportsLatest = true
override val client = network.cloudflareClient
private var csrfToken = ""
// Popular
override fun popularMangaRequest(page: Int) =
GET("$baseUrl/directorio?filtro=visitas&p=$page", headers)
override fun popularMangaRequest(page: Int) = GET(
"$baseUrl/directorio?genero=false" +
"&estado=false&filtro=visitas&tipo=false&adulto=${if (hideNSFWContent()) "0" else "false"}&orden=desc&p=$page",
headers
)
override fun popularMangaNextPageSelector() = ".page-item a[rel=next]"
override fun popularMangaSelector() = "#article-div a"
override fun popularMangaFromElement(element: Element): SManga = SManga.create().apply {
setUrlWithoutDomain(element.attr("href"))
thumbnail_url = element.select("img").attr("data-src")
@ -65,11 +77,12 @@ open class MangaMx : ParsedHttpSource() {
return MangasPage(mangas, hasNextPage)
}
// Latest
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/recientes?p=$page", headers)
override fun latestUpdatesNextPageSelector(): String? = popularMangaNextPageSelector()
override fun latestUpdatesSelector() = "div._1bJU3"
override fun latestUpdatesFromElement(element: Element): SManga = SManga.create().apply {
thumbnail_url = element.select("img").attr("data-src")
element.select("div a").apply {
@ -78,8 +91,6 @@ open class MangaMx : ParsedHttpSource() {
}
}
// Search
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
if (query.isNotBlank()) {
val formBody = FormBody.Builder()
@ -91,28 +102,32 @@ open class MangaMx : ParsedHttpSource() {
return POST("$baseUrl/buscar", searchHeaders, formBody)
} else {
val uri = Uri.parse("$baseUrl/directorio").buildUpon()
// Append uri filters
uri.appendQueryParameter(
"adulto",
if (hideNSFWContent()) { "0" } else { "1" }
)
for (filter in filters) {
when (filter) {
is StatusFilter -> uri.appendQueryParameter(
filter.name.toLowerCase(Locale.ROOT),
statusArray[filter.state].second
)
is FilterFilter -> uri.appendQueryParameter(
filter.name.toLowerCase(Locale.ROOT),
filterArray[filter.state].second
is SortBy -> {
uri.appendQueryParameter("filtro", sortables[filter.state!!.index].second)
uri.appendQueryParameter(
"orden",
if (filter.state!!.ascending) { "asc" } else { "desc" }
)
}
is TypeFilter -> uri.appendQueryParameter(
filter.name.toLowerCase(Locale.ROOT),
typedArray[filter.state].second
)
is AdultFilter -> uri.appendQueryParameter(
filter.name.toLowerCase(Locale.ROOT),
adultArray[filter.state].second
)
is OrderFilter -> uri.appendQueryParameter(
filter.name.toLowerCase(Locale.ROOT),
orderArray[filter.state].second
is GenreFilter -> uri.appendQueryParameter(
"genero",
genresArray[filter.state].second
)
}
}
@ -122,8 +137,11 @@ open class MangaMx : ParsedHttpSource() {
}
override fun searchMangaNextPageSelector(): String? = popularMangaNextPageSelector()
override fun searchMangaSelector(): String = popularMangaSelector()
override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element)
override fun searchMangaParse(response: Response): MangasPage {
if (!response.isSuccessful) throw Exception("Búsqueda fallida ${response.code()}")
if ("directorio" in response.request().url().toString()) {
@ -154,8 +172,6 @@ open class MangaMx : ParsedHttpSource() {
thumbnail_url = jsonElement["img"].string.replace("/thumb", "/cover")
}
// Details
override fun mangaDetailsParse(document: Document): SManga {
val manga = SManga.create()
manga.thumbnail_url = document.select("img[src*=cover]").attr("abs:src")
@ -175,8 +191,6 @@ open class MangaMx : ParsedHttpSource() {
return manga
}
// Chapters
override fun chapterListSelector(): String = "div#c_list a"
override fun chapterFromElement(element: Element): SChapter = SChapter.create().apply {
@ -190,13 +204,10 @@ open class MangaMx : ParsedHttpSource() {
return SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.US).parse(date)?.time ?: 0
}
// Pages
override fun pageListParse(document: Document): List<Page> {
val encoded = document.select("script:containsData(unicap)").firstOrNull()
?.data()?.substringAfter("'")?.substringBefore("'")?.reversed()
?: throw Exception("unicap not found")
val drop = encoded.length % 4
val decoded = Base64.decode(encoded.dropLast(drop), Base64.DEFAULT).toString(Charset.defaultCharset())
val path = decoded.substringBefore("||")
@ -207,43 +218,35 @@ open class MangaMx : ParsedHttpSource() {
override fun imageUrlParse(document: Document) = throw Exception("Not Used")
// Filters
override fun getFilterList() = FilterList(
Filter.Header("NOTA: ¡Ignorado si usa la búsqueda de texto!"),
Filter.Header("NOTA: Se ignoran si se usa el buscador"),
Filter.Separator(),
SortBy("Ordenar por", sortables),
StatusFilter("Estado", statusArray),
FilterFilter("Filtro", filterArray),
TypeFilter("Tipo", typedArray),
AdultFilter("Adulto", adultArray),
OrderFilter("Orden", orderArray)
GenreFilter("Géneros", genresArray)
)
private class StatusFilter(name: String, values: Array<Pair<String, String>>) :
Filter.Select<String>(name, values.map { it.first }.toTypedArray())
private class FilterFilter(name: String, values: Array<Pair<String, String>>) :
Filter.Select<String>(name, values.map { it.first }.toTypedArray())
private class TypeFilter(name: String, values: Array<Pair<String, String>>) :
Filter.Select<String>(name, values.map { it.first }.toTypedArray())
private class AdultFilter(name: String, values: Array<Pair<String, String>>) :
private class GenreFilter(name: String, values: Array<Pair<String, String>>) :
Filter.Select<String>(name, values.map { it.first }.toTypedArray())
private class OrderFilter(name: String, values: Array<Pair<String, String>>) :
Filter.Select<String>(name, values.map { it.first }.toTypedArray())
class SortBy(name: String, values: Array<Pair<String, String>>) : Filter.Sort(
name, values.map { it.first }.toTypedArray(),
Selection(0, false)
)
private val statusArray = arrayOf(
Pair("Estado", "false"),
Pair("En desarrollo", "1"),
Pair("Completo", "0")
)
private val filterArray = arrayOf(
Pair("Visitas", "visitas"),
Pair("Recientes", "id"),
Pair("Alfabético", "nombre")
)
private val typedArray = arrayOf(
Pair("Todo", "false"),
Pair("Mangas", "0"),
@ -252,13 +255,104 @@ open class MangaMx : ParsedHttpSource() {
Pair("Manhuas", "3"),
Pair("Novelas", "4")
)
private val adultArray = arrayOf(
Pair("Filtro adulto", "false"),
Pair("No mostrar +18", "0"),
Pair("Mostrar +18", "1")
private val sortables = arrayOf(
Pair("Visitas", "visitas"),
Pair("Recientes", "id"),
Pair("Alfabético", "nombre"),
)
private val orderArray = arrayOf(
Pair("Descendente", "desc"),
Pair("Ascendente", "asc")
/**
* Url: https://manga-mx.com/directorio/
* Last check: 27/03/2021
* JS script: Array.from(document.querySelectorAll('select[name="genero"] option'))
* .map(a => `Pair("${a.innerText}", "${a.value}")`).join(',\n')
*/
private val genresArray = arrayOf(
Pair("Todos", "false"),
Pair("Comedia", "1"),
Pair("Drama", "2"),
Pair("Acción", "3"),
Pair("Escolar", "4"),
Pair("Romance", "5"),
Pair("Ecchi", "6"),
Pair("Aventura", "7"),
Pair("Shōnen", "8"),
Pair("Shōjo", "9"),
Pair("Deportes", "10"),
Pair("Psicológico", "11"),
Pair("Fantasía", "12"),
Pair("Mecha", "13"),
Pair("Gore", "14"),
Pair("Yaoi", "15"),
Pair("Yuri", "16"),
Pair("Misterio", "17"),
Pair("Sobrenatural", "18"),
Pair("Seinen", "19"),
Pair("Ficción", "20"),
Pair("Harem", "21"),
Pair("Webtoon", "25"),
Pair("Histórico", "27"),
Pair("Músical", "30"),
Pair("Ciencia ficción", "31"),
Pair("Shōjo-ai", "32"),
Pair("Josei", "33"),
Pair("Magia", "34"),
Pair("Artes Marciales", "35"),
Pair("Horror", "36"),
Pair("Demonios", "37"),
Pair("Supervivencia", "38"),
Pair("Recuentos de la vida", "39"),
Pair("Shōnen ai", "40"),
Pair("Militar", "41"),
Pair("Eroge", "42"),
Pair("Isekai", "43")
)
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
override fun setupPreferenceScreen(screen: androidx.preference.PreferenceScreen) {
val contentPref = androidx.preference.CheckBoxPreference(screen.context).apply {
key = CONTENT_PREF
title = CONTENT_PREF_TITLE
summary = CONTENT_PREF_SUMMARY
setDefaultValue(CONTENT_PREF_DEFAULT_VALUE)
setOnPreferenceChangeListener { _, newValue ->
val checkValue = newValue as Boolean
preferences.edit().putBoolean(CONTENT_PREF, checkValue).commit()
}
}
screen.addPreference(contentPref)
}
override fun setupPreferenceScreen(screen: PreferenceScreen) {
val contentPref = CheckBoxPreference(screen.context).apply {
key = CONTENT_PREF
title = CONTENT_PREF_TITLE
summary = CONTENT_PREF_SUMMARY
setDefaultValue(CONTENT_PREF_DEFAULT_VALUE)
setOnPreferenceChangeListener { _, newValue ->
val checkValue = newValue as Boolean
preferences.edit().putBoolean(CONTENT_PREF, checkValue).commit()
}
}
screen.addPreference(contentPref)
}
private fun hideNSFWContent(): Boolean = preferences.getBoolean(CONTENT_PREF, CONTENT_PREF_DEFAULT_VALUE)
companion object {
private const val CONTENT_PREF = "showNSFWContent"
private const val CONTENT_PREF_TITLE = "Ocultar contenido +18"
private const val CONTENT_PREF_SUMMARY = "Ocultar el contenido erótico en explorar y buscar, no funciona en los mangas recientes."
private const val CONTENT_PREF_DEFAULT_VALUE = false
}
}

View File

@ -5,7 +5,7 @@ ext {
extName = 'TuMangaOnline'
pkgNameSuffix = 'es.tumangaonline'
extClass = '.TuMangaOnline'
extVersionCode = 32
extVersionCode = 33
libVersion = '1.2'
}

View File

@ -140,8 +140,8 @@ class TuMangaOnline : ConfigurableSource, ParsedHttpSource() {
is GenreList -> {
filter.state.forEach { genre ->
when (genre.state) {
Filter.TriState.STATE_INCLUDE -> url.addQueryParameter("exclude_genders[]", genre.id)
Filter.TriState.STATE_EXCLUDE -> url.addQueryParameter("genders[]", genre.id)
Filter.TriState.STATE_INCLUDE -> url.addQueryParameter("genders[]", genre.id)
Filter.TriState.STATE_EXCLUDE -> url.addQueryParameter("exclude_genders[]", genre.id)
}
}
}