LectorTmo: Remove LectorManga and fix crash on some devices (#7508)
* override fetch methods * remove lectorManga
This commit is contained in:
parent
7dd76fe0c9
commit
2147b87816
|
@ -1,7 +1,7 @@
|
||||||
ext {
|
ext {
|
||||||
extName = 'TuMangaOnline / LectorManga'
|
extName = 'TuMangaOnline'
|
||||||
extClass = '.LectorTmoFactory'
|
extClass = '.LectorTmo'
|
||||||
extVersionCode = 4
|
extVersionCode = 6
|
||||||
isNsfw = true
|
isNsfw = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -4,13 +4,11 @@ import android.annotation.SuppressLint
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
import androidx.preference.CheckBoxPreference
|
import androidx.preference.CheckBoxPreference
|
||||||
import androidx.preference.ListPreference
|
|
||||||
import androidx.preference.PreferenceScreen
|
import androidx.preference.PreferenceScreen
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.POST
|
import eu.kanade.tachiyomi.network.POST
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||||
import eu.kanade.tachiyomi.network.interceptor.rateLimitHost
|
|
||||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||||
import eu.kanade.tachiyomi.source.model.Filter
|
import eu.kanade.tachiyomi.source.model.Filter
|
||||||
import eu.kanade.tachiyomi.source.model.FilterList
|
import eu.kanade.tachiyomi.source.model.FilterList
|
||||||
|
@ -34,16 +32,20 @@ import java.security.SecureRandom
|
||||||
import java.security.cert.X509Certificate
|
import java.security.cert.X509Certificate
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
import javax.net.ssl.SSLContext
|
import javax.net.ssl.SSLContext
|
||||||
import javax.net.ssl.TrustManager
|
import javax.net.ssl.TrustManager
|
||||||
import javax.net.ssl.X509TrustManager
|
import javax.net.ssl.X509TrustManager
|
||||||
|
|
||||||
abstract class LectorTmo(
|
class LectorTmo : ParsedHttpSource(), ConfigurableSource {
|
||||||
override val name: String,
|
|
||||||
override val baseUrl: String,
|
override val id = 4146344224513899730
|
||||||
override val lang: String,
|
|
||||||
private val rateLimitClient: OkHttpClient,
|
override val name = "TuMangaOnline"
|
||||||
) : ParsedHttpSource(), ConfigurableSource {
|
|
||||||
|
override val baseUrl = "https://zonatmo.com"
|
||||||
|
|
||||||
|
override val lang = "es"
|
||||||
|
|
||||||
private val preferences: SharedPreferences by lazy {
|
private val preferences: SharedPreferences by lazy {
|
||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||||
|
@ -56,19 +58,6 @@ abstract class LectorTmo(
|
||||||
.set("Referer", "$baseUrl/")
|
.set("Referer", "$baseUrl/")
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
protected open val imageCDNUrls = arrayOf(
|
|
||||||
"https://img1.japanreader.com",
|
|
||||||
"https://japanreader.com",
|
|
||||||
"https://imgtmo.com",
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun OkHttpClient.Builder.rateLimitImageCDNs(hosts: Array<String>, permits: Int, period: Long): OkHttpClient.Builder {
|
|
||||||
hosts.forEach { host ->
|
|
||||||
rateLimitHost(host.toHttpUrl(), permits, period)
|
|
||||||
}
|
|
||||||
return this
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun OkHttpClient.Builder.ignoreAllSSLErrors(): OkHttpClient.Builder {
|
private fun OkHttpClient.Builder.ignoreAllSSLErrors(): OkHttpClient.Builder {
|
||||||
val naiveTrustManager = @SuppressLint("CustomX509TrustManager")
|
val naiveTrustManager = @SuppressLint("CustomX509TrustManager")
|
||||||
object : X509TrustManager {
|
object : X509TrustManager {
|
||||||
|
@ -77,7 +66,7 @@ abstract class LectorTmo(
|
||||||
override fun checkServerTrusted(certs: Array<X509Certificate>, authType: String) = Unit
|
override fun checkServerTrusted(certs: Array<X509Certificate>, authType: String) = Unit
|
||||||
}
|
}
|
||||||
|
|
||||||
val insecureSocketFactory = SSLContext.getInstance("TLSv1.2").apply {
|
val insecureSocketFactory = SSLContext.getInstance("SSL").apply {
|
||||||
val trustAllCerts = arrayOf<TrustManager>(naiveTrustManager)
|
val trustAllCerts = arrayOf<TrustManager>(naiveTrustManager)
|
||||||
init(null, trustAllCerts, SecureRandom())
|
init(null, trustAllCerts, SecureRandom())
|
||||||
}.socketFactory
|
}.socketFactory
|
||||||
|
@ -87,28 +76,18 @@ abstract class LectorTmo(
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
private val ignoreSslClient: OkHttpClient by lazy {
|
override val client: OkHttpClient by lazy {
|
||||||
rateLimitClient.newBuilder()
|
network.cloudflareClient.newBuilder()
|
||||||
.ignoreAllSSLErrors()
|
.ignoreAllSSLErrors()
|
||||||
.followRedirects(false)
|
.rateLimit(3, 1, TimeUnit.SECONDS)
|
||||||
.rateLimit(
|
|
||||||
preferences.getString(IMAGE_CDN_RATELIMIT_PREF, IMAGE_CDN_RATELIMIT_PREF_DEFAULT_VALUE)!!.toInt(),
|
|
||||||
60,
|
|
||||||
)
|
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
private var lastCFDomain: String = ""
|
private var lastCFDomain: String = ""
|
||||||
override val client: OkHttpClient by lazy {
|
|
||||||
rateLimitClient.newBuilder()
|
// Used on all request except on image requests
|
||||||
.addInterceptor { chain ->
|
private val safeClient: OkHttpClient by lazy {
|
||||||
val request = chain.request()
|
network.cloudflareClient.newBuilder()
|
||||||
val url = request.url
|
|
||||||
if (url.fragment == "imagereq") {
|
|
||||||
return@addInterceptor ignoreSslClient.newCall(request).execute()
|
|
||||||
}
|
|
||||||
chain.proceed(request)
|
|
||||||
}
|
|
||||||
.addInterceptor { chain ->
|
.addInterceptor { chain ->
|
||||||
if (!getSaveLastCFUrlPref()) return@addInterceptor chain.proceed(chain.request())
|
if (!getSaveLastCFUrlPref()) return@addInterceptor chain.proceed(chain.request())
|
||||||
val request = chain.request()
|
val request = chain.request()
|
||||||
|
@ -118,22 +97,21 @@ abstract class LectorTmo(
|
||||||
}
|
}
|
||||||
response
|
response
|
||||||
}
|
}
|
||||||
.rateLimitHost(
|
.rateLimit(1, 3, TimeUnit.SECONDS)
|
||||||
baseUrl.toHttpUrl(),
|
|
||||||
preferences.getString(WEB_RATELIMIT_PREF, WEB_RATELIMIT_PREF_DEFAULT_VALUE)!!.toInt(),
|
|
||||||
60,
|
|
||||||
)
|
|
||||||
.rateLimitImageCDNs(
|
|
||||||
imageCDNUrls,
|
|
||||||
preferences.getString(IMAGE_CDN_RATELIMIT_PREF, IMAGE_CDN_RATELIMIT_PREF_DEFAULT_VALUE)!!.toInt(),
|
|
||||||
60,
|
|
||||||
)
|
|
||||||
.build()
|
.build()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Marks erotic content as false and excludes: Ecchi(6), GirlsLove(17), BoysLove(18), Harem(19), Trap(94) genders
|
// Marks erotic content as false and excludes: Ecchi(6), GirlsLove(17), BoysLove(18), Harem(19), Trap(94) genders
|
||||||
private fun getSFWUrlPart(): String = if (getSFWModePref()) "&exclude_genders%5B%5D=6&exclude_genders%5B%5D=17&exclude_genders%5B%5D=18&exclude_genders%5B%5D=19&exclude_genders%5B%5D=94&erotic=false" else ""
|
private fun getSFWUrlPart(): String = if (getSFWModePref()) "&exclude_genders%5B%5D=6&exclude_genders%5B%5D=17&exclude_genders%5B%5D=18&exclude_genders%5B%5D=19&exclude_genders%5B%5D=94&erotic=false" else ""
|
||||||
|
|
||||||
|
override fun fetchPopularManga(page: Int): Observable<MangasPage> {
|
||||||
|
return safeClient.newCall(popularMangaRequest(page))
|
||||||
|
.asObservableSuccess()
|
||||||
|
.map { response ->
|
||||||
|
popularMangaParse(response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun popularMangaRequest(page: Int) = GET("$baseUrl/library?order_item=likes_count&order_dir=desc&filter_by=title${getSFWUrlPart()}&_pg=1&page=$page", tmoHeaders)
|
override fun popularMangaRequest(page: Int) = GET("$baseUrl/library?order_item=likes_count&order_dir=desc&filter_by=title${getSFWUrlPart()}&_pg=1&page=$page", tmoHeaders)
|
||||||
|
|
||||||
override fun popularMangaNextPageSelector() = "a[rel='next']"
|
override fun popularMangaNextPageSelector() = "a[rel='next']"
|
||||||
|
@ -148,6 +126,14 @@ abstract class LectorTmo(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun fetchLatestUpdates(page: Int): Observable<MangasPage> {
|
||||||
|
return safeClient.newCall(latestUpdatesRequest(page))
|
||||||
|
.asObservableSuccess()
|
||||||
|
.map { response ->
|
||||||
|
latestUpdatesParse(response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/library?order_item=creation&order_dir=desc&filter_by=title${getSFWUrlPart()}&_pg=1&page=$page", tmoHeaders)
|
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/library?order_item=creation&order_dir=desc&filter_by=title${getSFWUrlPart()}&_pg=1&page=$page", tmoHeaders)
|
||||||
|
|
||||||
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
|
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
|
||||||
|
@ -160,7 +146,7 @@ abstract class LectorTmo(
|
||||||
return if (query.startsWith(PREFIX_SLUG_SEARCH)) {
|
return if (query.startsWith(PREFIX_SLUG_SEARCH)) {
|
||||||
val realQuery = query.removePrefix(PREFIX_SLUG_SEARCH)
|
val realQuery = query.removePrefix(PREFIX_SLUG_SEARCH)
|
||||||
|
|
||||||
client.newCall(searchMangaBySlugRequest(realQuery))
|
safeClient.newCall(searchMangaBySlugRequest(realQuery))
|
||||||
.asObservableSuccess()
|
.asObservableSuccess()
|
||||||
.map { response ->
|
.map { response ->
|
||||||
val details = mangaDetailsParse(response)
|
val details = mangaDetailsParse(response)
|
||||||
|
@ -168,7 +154,7 @@ abstract class LectorTmo(
|
||||||
MangasPage(listOf(details), false)
|
MangasPage(listOf(details), false)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
client.newCall(searchMangaRequest(page, query, filters))
|
safeClient.newCall(searchMangaRequest(page, query, filters))
|
||||||
.asObservableSuccess()
|
.asObservableSuccess()
|
||||||
.map { response ->
|
.map { response ->
|
||||||
searchMangaParse(response)
|
searchMangaParse(response)
|
||||||
|
@ -241,6 +227,14 @@ abstract class LectorTmo(
|
||||||
return super.getMangaUrl(manga)
|
return super.getMangaUrl(manga)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun fetchMangaDetails(manga: SManga): Observable<SManga> {
|
||||||
|
return safeClient.newCall(mangaDetailsRequest(manga))
|
||||||
|
.asObservableSuccess()
|
||||||
|
.map { response ->
|
||||||
|
mangaDetailsParse(response).apply { initialized = true }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun mangaDetailsRequest(manga: SManga) = GET(baseUrl + manga.url, tmoHeaders)
|
override fun mangaDetailsRequest(manga: SManga) = GET(baseUrl + manga.url, tmoHeaders)
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
||||||
|
@ -257,19 +251,27 @@ abstract class LectorTmo(
|
||||||
thumbnail_url = document.select(".book-thumbnail").attr("src")
|
thumbnail_url = document.select(".book-thumbnail").attr("src")
|
||||||
}
|
}
|
||||||
|
|
||||||
protected fun parseStatus(status: String) = when {
|
private fun parseStatus(status: String) = when {
|
||||||
status.contains("Publicándose") -> SManga.ONGOING
|
status.contains("Publicándose") -> SManga.ONGOING
|
||||||
status.contains("Finalizado") -> SManga.COMPLETED
|
status.contains("Finalizado") -> SManga.COMPLETED
|
||||||
else -> SManga.UNKNOWN
|
else -> SManga.UNKNOWN
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open val oneShotChapterName = "One Shot"
|
private val oneShotChapterName = "One Shot"
|
||||||
|
|
||||||
override fun getChapterUrl(chapter: SChapter): String {
|
override fun getChapterUrl(chapter: SChapter): String {
|
||||||
if (lastCFDomain.isNotEmpty()) return lastCFDomain.also { lastCFDomain = "" }
|
if (lastCFDomain.isNotEmpty()) return lastCFDomain.also { lastCFDomain = "" }
|
||||||
return super.getChapterUrl(chapter)
|
return super.getChapterUrl(chapter)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun fetchChapterList(manga: SManga): Observable<List<SChapter>> {
|
||||||
|
return safeClient.newCall(chapterListRequest(manga))
|
||||||
|
.asObservableSuccess()
|
||||||
|
.map { response ->
|
||||||
|
chapterListParse(response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun chapterListRequest(manga: SManga) = mangaDetailsRequest(manga)
|
override fun chapterListRequest(manga: SManga) = mangaDetailsRequest(manga)
|
||||||
|
|
||||||
override fun chapterListParse(response: Response): List<SChapter> {
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
|
@ -294,15 +296,15 @@ abstract class LectorTmo(
|
||||||
return chapters
|
return chapters
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open val oneShotChapterListSelector = "div.chapter-list-element > ul.list-group li.list-group-item"
|
private val oneShotChapterListSelector = "div.chapter-list-element > ul.list-group li.list-group-item"
|
||||||
|
|
||||||
protected open val regularChapterListSelector = "div.chapters > ul.list-group li.p-0.list-group-item"
|
private val regularChapterListSelector = "div.chapters > ul.list-group li.p-0.list-group-item"
|
||||||
|
|
||||||
override fun chapterListSelector() = throw UnsupportedOperationException()
|
override fun chapterListSelector() = throw UnsupportedOperationException()
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element) = throw UnsupportedOperationException()
|
override fun chapterFromElement(element: Element) = throw UnsupportedOperationException()
|
||||||
|
|
||||||
protected open fun chapterFromElement(element: Element, chName: String) = SChapter.create().apply {
|
private fun chapterFromElement(element: Element, chName: String) = SChapter.create().apply {
|
||||||
url = element.select("div.row > .text-right > a").attr("href")
|
url = element.select("div.row > .text-right > a").attr("href")
|
||||||
name = chName
|
name = chName
|
||||||
scanlator = element.select("div.col-md-6.text-truncate").text()
|
scanlator = element.select("div.col-md-6.text-truncate").text()
|
||||||
|
@ -311,11 +313,19 @@ abstract class LectorTmo(
|
||||||
} ?: 0
|
} ?: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
protected open fun parseChapterDate(date: String): Long {
|
private fun parseChapterDate(date: String): Long {
|
||||||
return SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
|
return SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
|
||||||
.parse(date)?.time ?: 0
|
.parse(date)?.time ?: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun fetchPageList(chapter: SChapter): Observable<List<Page>> {
|
||||||
|
return safeClient.newCall(pageListRequest(chapter))
|
||||||
|
.asObservableSuccess()
|
||||||
|
.map { response ->
|
||||||
|
pageListParse(response)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
override fun pageListRequest(chapter: SChapter): Request {
|
override fun pageListRequest(chapter: SChapter): Request {
|
||||||
return GET(chapter.url, tmoHeaders)
|
return GET(chapter.url, tmoHeaders)
|
||||||
}
|
}
|
||||||
|
@ -440,7 +450,7 @@ abstract class LectorTmo(
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun imageRequest(page: Page) = GET(
|
override fun imageRequest(page: Page) = GET(
|
||||||
url = page.imageUrl!! + "#imagereq",
|
url = page.imageUrl!!,
|
||||||
headers = headers.newBuilder()
|
headers = headers.newBuilder()
|
||||||
.set("Referer", page.url.substringBefore("news/"))
|
.set("Referer", page.url.substringBefore("news/"))
|
||||||
.build(),
|
.build(),
|
||||||
|
@ -564,11 +574,11 @@ abstract class LectorTmo(
|
||||||
Genre("Trap", "94"),
|
Genre("Trap", "94"),
|
||||||
)
|
)
|
||||||
|
|
||||||
protected fun getScanlatorPref(): Boolean = preferences.getBoolean(SCANLATOR_PREF, SCANLATOR_PREF_DEFAULT_VALUE)
|
private fun getScanlatorPref(): Boolean = preferences.getBoolean(SCANLATOR_PREF, SCANLATOR_PREF_DEFAULT_VALUE)
|
||||||
|
|
||||||
protected fun getSFWModePref(): Boolean = preferences.getBoolean(SFW_MODE_PREF, SFW_MODE_PREF_DEFAULT_VALUE)
|
private fun getSFWModePref(): Boolean = preferences.getBoolean(SFW_MODE_PREF, SFW_MODE_PREF_DEFAULT_VALUE)
|
||||||
|
|
||||||
protected fun getSaveLastCFUrlPref(): Boolean = preferences.getBoolean(SAVE_LAST_CF_URL_PREF, SAVE_LAST_CF_URL_PREF_DEFAULT_VALUE)
|
private fun getSaveLastCFUrlPref(): Boolean = preferences.getBoolean(SAVE_LAST_CF_URL_PREF, SAVE_LAST_CF_URL_PREF_DEFAULT_VALUE)
|
||||||
|
|
||||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||||
val sfwModePref = CheckBoxPreference(screen.context).apply {
|
val sfwModePref = CheckBoxPreference(screen.context).apply {
|
||||||
|
@ -585,25 +595,6 @@ abstract class LectorTmo(
|
||||||
setDefaultValue(SCANLATOR_PREF_DEFAULT_VALUE)
|
setDefaultValue(SCANLATOR_PREF_DEFAULT_VALUE)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Rate limit
|
|
||||||
val apiRateLimitPreference = ListPreference(screen.context).apply {
|
|
||||||
key = WEB_RATELIMIT_PREF
|
|
||||||
title = WEB_RATELIMIT_PREF_TITLE
|
|
||||||
summary = WEB_RATELIMIT_PREF_SUMMARY
|
|
||||||
entries = ENTRIES_ARRAY
|
|
||||||
entryValues = ENTRIES_ARRAY
|
|
||||||
setDefaultValue(WEB_RATELIMIT_PREF_DEFAULT_VALUE)
|
|
||||||
}
|
|
||||||
|
|
||||||
val imgCDNRateLimitPreference = ListPreference(screen.context).apply {
|
|
||||||
key = IMAGE_CDN_RATELIMIT_PREF
|
|
||||||
title = IMAGE_CDN_RATELIMIT_PREF_TITLE
|
|
||||||
summary = IMAGE_CDN_RATELIMIT_PREF_SUMMARY
|
|
||||||
entries = ENTRIES_ARRAY
|
|
||||||
entryValues = ENTRIES_ARRAY
|
|
||||||
setDefaultValue(IMAGE_CDN_RATELIMIT_PREF_DEFAULT_VALUE)
|
|
||||||
}
|
|
||||||
|
|
||||||
val saveLastCFUrlPreference = CheckBoxPreference(screen.context).apply {
|
val saveLastCFUrlPreference = CheckBoxPreference(screen.context).apply {
|
||||||
key = SAVE_LAST_CF_URL_PREF
|
key = SAVE_LAST_CF_URL_PREF
|
||||||
title = SAVE_LAST_CF_URL_PREF_TITLE
|
title = SAVE_LAST_CF_URL_PREF_TITLE
|
||||||
|
@ -613,8 +604,6 @@ abstract class LectorTmo(
|
||||||
|
|
||||||
screen.addPreference(sfwModePref)
|
screen.addPreference(sfwModePref)
|
||||||
screen.addPreference(scanlatorPref)
|
screen.addPreference(scanlatorPref)
|
||||||
screen.addPreference(apiRateLimitPreference)
|
|
||||||
screen.addPreference(imgCDNRateLimitPreference)
|
|
||||||
screen.addPreference(saveLastCFUrlPreference)
|
screen.addPreference(saveLastCFUrlPreference)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -633,23 +622,11 @@ abstract class LectorTmo(
|
||||||
private const val SFW_MODE_PREF_DEFAULT_VALUE = false
|
private const val SFW_MODE_PREF_DEFAULT_VALUE = false
|
||||||
private val SFW_MODE_PREF_EXCLUDE_GENDERS = listOf("6", "17", "18", "19")
|
private val SFW_MODE_PREF_EXCLUDE_GENDERS = listOf("6", "17", "18", "19")
|
||||||
|
|
||||||
private const val WEB_RATELIMIT_PREF = "webRatelimitPreference"
|
|
||||||
private const val WEB_RATELIMIT_PREF_TITLE = "Ratelimit por minuto para el sitio web"
|
|
||||||
private const val WEB_RATELIMIT_PREF_SUMMARY = "Este valor afecta la cantidad de solicitudes de red a la URL de TMO. Reducir este valor puede disminuir la posibilidad de obtener un error HTTP 429, pero la velocidad de descarga será más lenta. Se requiere reiniciar la app. \nValor actual: %s"
|
|
||||||
private const val WEB_RATELIMIT_PREF_DEFAULT_VALUE = "8"
|
|
||||||
|
|
||||||
private const val IMAGE_CDN_RATELIMIT_PREF = "imgCDNRatelimitPreference"
|
|
||||||
private const val IMAGE_CDN_RATELIMIT_PREF_TITLE = "Ratelimit por minuto para descarga de imágenes"
|
|
||||||
private const val IMAGE_CDN_RATELIMIT_PREF_SUMMARY = "Este valor afecta la cantidad de solicitudes de red para descargar imágenes. Reducir este valor puede disminuir errores al cargar imagenes, pero la velocidad de descarga será más lenta. Se requiere reiniciar la app. \nValor actual: %s"
|
|
||||||
private const val IMAGE_CDN_RATELIMIT_PREF_DEFAULT_VALUE = "50"
|
|
||||||
|
|
||||||
private const val SAVE_LAST_CF_URL_PREF = "saveLastCFUrlPreference"
|
private const val SAVE_LAST_CF_URL_PREF = "saveLastCFUrlPreference"
|
||||||
private const val SAVE_LAST_CF_URL_PREF_TITLE = "Guardar la última URL con error de Cloudflare"
|
private const val SAVE_LAST_CF_URL_PREF_TITLE = "Guardar la última URL con error de Cloudflare"
|
||||||
private const val SAVE_LAST_CF_URL_PREF_SUMMARY = "Guarda la última URL con error de Cloudflare para que se pueda acceder a ella al abrir la serie en WebView."
|
private const val SAVE_LAST_CF_URL_PREF_SUMMARY = "Guarda la última URL con error de Cloudflare para que se pueda acceder a ella al abrir la serie en WebView."
|
||||||
private const val SAVE_LAST_CF_URL_PREF_DEFAULT_VALUE = true
|
private const val SAVE_LAST_CF_URL_PREF_DEFAULT_VALUE = true
|
||||||
|
|
||||||
private val ENTRIES_ARRAY = listOf(1, 2, 3, 5, 6, 7, 8, 9, 10, 15, 20, 30, 40, 50, 100).map { i -> i.toString() }.toTypedArray()
|
|
||||||
|
|
||||||
const val PREFIX_LIBRARY = "library"
|
const val PREFIX_LIBRARY = "library"
|
||||||
const val PREFIX_SLUG_SEARCH = "slug:"
|
const val PREFIX_SLUG_SEARCH = "slug:"
|
||||||
|
|
||||||
|
|
|
@ -1,83 +0,0 @@
|
||||||
package eu.kanade.tachiyomi.extension.es.lectortmo
|
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
|
||||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
|
||||||
import eu.kanade.tachiyomi.source.SourceFactory
|
|
||||||
import eu.kanade.tachiyomi.source.model.SChapter
|
|
||||||
import eu.kanade.tachiyomi.source.model.SManga
|
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
|
||||||
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.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
class LectorTmoFactory : SourceFactory {
|
|
||||||
|
|
||||||
override fun createSources() = listOf(
|
|
||||||
LectorManga(),
|
|
||||||
TuMangaOnline(),
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val rateLimitClient = Injekt.get<NetworkHelper>().cloudflareClient.newBuilder()
|
|
||||||
.rateLimit(1, 1500, TimeUnit.MILLISECONDS)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
class TuMangaOnline : LectorTmo("TuMangaOnline", "https://zonatmo.com", "es", rateLimitClient) {
|
|
||||||
override val id = 4146344224513899730
|
|
||||||
}
|
|
||||||
|
|
||||||
class LectorManga : LectorTmo("LectorManga", "https://lectormanga.com", "es", rateLimitClient) {
|
|
||||||
override val id = 7925520943983324764
|
|
||||||
|
|
||||||
override fun popularMangaSelector() = ".col-6 .card"
|
|
||||||
|
|
||||||
override fun popularMangaFromElement(element: Element) = SManga.create().apply {
|
|
||||||
setUrlWithoutDomain(element.select("a").attr("href"))
|
|
||||||
title = element.select("a").text()
|
|
||||||
thumbnail_url = element.select("img").attr("src")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
|
||||||
document.selectFirst("h1:has(small)")?.let { title = it.ownText() }
|
|
||||||
genre = document.select("a.py-2").joinToString(", ") {
|
|
||||||
it.text()
|
|
||||||
}
|
|
||||||
description = document.select(".col-12.mt-2").text()
|
|
||||||
status = parseStatus(document.select(".status-publishing").text())
|
|
||||||
thumbnail_url = document.select(".text-center img.img-fluid").attr("src")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun chapterListParse(response: Response): List<SChapter> = mutableListOf<SChapter>().apply {
|
|
||||||
val document = response.asJsoup()
|
|
||||||
|
|
||||||
// One-shot
|
|
||||||
if (document.select("#chapters").isEmpty()) {
|
|
||||||
return document.select(oneShotChapterListSelector).map { chapterFromElement(it, oneShotChapterName) }
|
|
||||||
}
|
|
||||||
|
|
||||||
// Regular list of chapters
|
|
||||||
val chapterNames = document.select("#chapters h4.text-truncate")
|
|
||||||
val chapterInfos = document.select("#chapters .chapter-list")
|
|
||||||
|
|
||||||
chapterNames.forEachIndexed { index, _ ->
|
|
||||||
val scanlator = chapterInfos[index].select("li")
|
|
||||||
if (getScanlatorPref()) {
|
|
||||||
scanlator.forEach { add(chapterFromElement(it, chapterNames[index].text())) }
|
|
||||||
} else {
|
|
||||||
scanlator.last { add(chapterFromElement(it, chapterNames[index].text())) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element, chName: String) = SChapter.create().apply {
|
|
||||||
url = element.select("div.row > .text-right > a").attr("href")
|
|
||||||
name = chName
|
|
||||||
scanlator = element.select("div.col-12.text-truncate span").text()
|
|
||||||
date_upload = element.select("span.badge.badge-primary.p-2").first()?.text()?.let {
|
|
||||||
parseChapterDate(it)
|
|
||||||
} ?: 0
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue