Update TMO, LectorTMO & TMOHentai (#6307)
* Add configurable rate limit, image CDN rate limit and SFW mode. * Add configurable image download mode (cascade/paginated). * Configurable ratelimit and image CDN ratelimit. * Fix redundant title
This commit is contained in:
parent
59b380205f
commit
135e08b754
@ -5,8 +5,12 @@ ext {
|
|||||||
extName = 'LectorManga'
|
extName = 'LectorManga'
|
||||||
pkgNameSuffix = 'es.lectormanga'
|
pkgNameSuffix = 'es.lectormanga'
|
||||||
extClass = '.LectorManga'
|
extClass = '.LectorManga'
|
||||||
extVersionCode = 14
|
extVersionCode = 15
|
||||||
libVersion = '1.2'
|
libVersion = '1.2'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation project(':lib-ratelimit')
|
||||||
|
}
|
||||||
|
|
||||||
apply from: "$rootDir/common.gradle"
|
apply from: "$rootDir/common.gradle"
|
||||||
|
@ -2,8 +2,10 @@ package eu.kanade.tachiyomi.extension.es.lectormanga
|
|||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
|
import android.support.v7.preference.CheckBoxPreference
|
||||||
import android.support.v7.preference.ListPreference
|
import android.support.v7.preference.ListPreference
|
||||||
import android.support.v7.preference.PreferenceScreen
|
import android.support.v7.preference.PreferenceScreen
|
||||||
|
import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||||
@ -15,8 +17,8 @@ import eu.kanade.tachiyomi.source.model.SChapter
|
|||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import okhttp3.Headers
|
|
||||||
import okhttp3.HttpUrl
|
import okhttp3.HttpUrl
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
@ -27,9 +29,6 @@ import uy.kohesive.injekt.api.get
|
|||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
|
||||||
/**
|
|
||||||
* Note: this source is similar to TuMangaOnline.
|
|
||||||
*/
|
|
||||||
class LectorManga : ConfigurableSource, ParsedHttpSource() {
|
class LectorManga : ConfigurableSource, ParsedHttpSource() {
|
||||||
|
|
||||||
override val name = "LectorManga"
|
override val name = "LectorManga"
|
||||||
@ -40,14 +39,29 @@ class LectorManga : ConfigurableSource, ParsedHttpSource() {
|
|||||||
|
|
||||||
override val supportsLatest = true
|
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"
|
private val imageCDNUrl = "https://img1.followmanga.com"
|
||||||
|
|
||||||
override fun headersBuilder(): Headers.Builder {
|
private val preferences: SharedPreferences by lazy {
|
||||||
return Headers.Builder()
|
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||||
.add("User-Agent", userAgent)
|
|
||||||
.add("Referer", "$baseUrl/")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val webRateLimitInterceptor = SpecificHostRateLimitInterceptor(
|
||||||
|
HttpUrl.parse(baseUrl)!!,
|
||||||
|
preferences.getString(WEB_RATELIMIT_PREF, WEB_RATELIMIT_PREF_DEFAULT_VALUE)!!.toInt(),
|
||||||
|
60
|
||||||
|
)
|
||||||
|
|
||||||
|
private val imageCDNRateLimitInterceptor = SpecificHostRateLimitInterceptor(
|
||||||
|
HttpUrl.parse(imageCDNUrl)!!,
|
||||||
|
preferences.getString(IMAGE_CDN_RATELIMIT_PREF, IMAGE_CDN_RATELIMIT_PREF_DEFAULT_VALUE)!!.toInt(),
|
||||||
|
60
|
||||||
|
)
|
||||||
|
|
||||||
|
override val client: OkHttpClient = network.client.newBuilder()
|
||||||
|
.addNetworkInterceptor(webRateLimitInterceptor)
|
||||||
|
.addNetworkInterceptor(imageCDNRateLimitInterceptor)
|
||||||
|
.build()
|
||||||
|
|
||||||
override fun popularMangaRequest(page: Int) = GET("$baseUrl/library?order_item=likes_count&order_dir=desc&type=&filter_by=title&page=$page", headers)
|
override fun popularMangaRequest(page: Int) = GET("$baseUrl/library?order_item=likes_count&order_dir=desc&type=&filter_by=title&page=$page", headers)
|
||||||
|
|
||||||
override fun popularMangaNextPageSelector() = ".pagination .page-item:not(.disabled) a[rel='next']"
|
override fun popularMangaNextPageSelector() = ".pagination .page-item:not(.disabled) a[rel='next']"
|
||||||
@ -176,17 +190,16 @@ class LectorManga : ConfigurableSource, ParsedHttpSource() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Regular list of chapters
|
// Regular list of chapters
|
||||||
val dupselect = getduppref()!!
|
|
||||||
val chapterNames = document.select("#chapters h4.text-truncate")
|
val chapterNames = document.select("#chapters h4.text-truncate")
|
||||||
val chapterNumbers = chapterNames.map { it.text().substringAfter("Capítulo").substringBefore("|").trim().toFloat() }
|
val chapterNumbers = chapterNames.map { it.text().substringAfter("Capítulo").substringBefore("|").trim().toFloat() }
|
||||||
val chapterInfos = document.select("#chapters .chapter-list")
|
val chapterInfos = document.select("#chapters .chapter-list")
|
||||||
|
|
||||||
chapterNames.forEachIndexed { index, _ ->
|
chapterNames.forEachIndexed { index, _ ->
|
||||||
val scanlator = chapterInfos[index].select("li")
|
val scanlator = chapterInfos[index].select("li")
|
||||||
if (dupselect == "one") {
|
if (getScanlatorPref()) {
|
||||||
scanlator.last { add(regularChapterFromElement(chapterNames[index].text(), it, chapterNumbers[index])) }
|
|
||||||
} else {
|
|
||||||
scanlator.forEach { add(regularChapterFromElement(chapterNames[index].text(), it, chapterNumbers[index])) }
|
scanlator.forEach { add(regularChapterFromElement(chapterNames[index].text(), it, chapterNumbers[index])) }
|
||||||
|
} else {
|
||||||
|
scanlator.last { add(regularChapterFromElement(chapterNames[index].text(), it, chapterNumbers[index])) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -224,9 +237,9 @@ class LectorManga : ConfigurableSource, ParsedHttpSource() {
|
|||||||
val currentUrl = client.newCall(GET(chapter.url, headers)).execute().asJsoup().body().baseUri()
|
val currentUrl = client.newCall(GET(chapter.url, headers)).execute().asJsoup().body().baseUri()
|
||||||
|
|
||||||
// Get /cascade instead of /paginate to get all pages at once
|
// Get /cascade instead of /paginate to get all pages at once
|
||||||
val newUrl = if (getPageMethod() == "cascade" && currentUrl.contains("paginated")) {
|
val newUrl = if (getPageMethodPref() == "cascade" && currentUrl.contains("paginated")) {
|
||||||
currentUrl.substringBefore("paginated") + "cascade"
|
currentUrl.substringBefore("paginated") + "cascade"
|
||||||
} else if (getPageMethod() == "paginated" && currentUrl.contains("cascade")) {
|
} else if (getPageMethodPref() == "paginated" && currentUrl.contains("cascade")) {
|
||||||
currentUrl.substringBefore("cascade") + "paginated"
|
currentUrl.substringBefore("cascade") + "paginated"
|
||||||
} else currentUrl
|
} else currentUrl
|
||||||
|
|
||||||
@ -234,7 +247,7 @@ class LectorManga : ConfigurableSource, ParsedHttpSource() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> = mutableListOf<Page>().apply {
|
override fun pageListParse(document: Document): List<Page> = mutableListOf<Page>().apply {
|
||||||
if (getPageMethod() == "cascade") {
|
if (getPageMethodPref() == "cascade") {
|
||||||
document.select("div.viewer-container img").forEach {
|
document.select("div.viewer-container img").forEach {
|
||||||
add(
|
add(
|
||||||
Page(
|
Page(
|
||||||
@ -410,91 +423,192 @@ class LectorManga : ConfigurableSource, ParsedHttpSource() {
|
|||||||
fun toUriPart() = vals[state].second
|
fun toUriPart() = vals[state].second
|
||||||
}
|
}
|
||||||
|
|
||||||
// Preferences
|
|
||||||
|
|
||||||
private val preferences: SharedPreferences by lazy {
|
|
||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setupPreferenceScreen(screen: androidx.preference.PreferenceScreen) {
|
override fun setupPreferenceScreen(screen: androidx.preference.PreferenceScreen) {
|
||||||
val deduppref = androidx.preference.ListPreference(screen.context).apply {
|
|
||||||
key = DEDUP_PREF_Title
|
val scanlatorPref = androidx.preference.CheckBoxPreference(screen.context).apply {
|
||||||
title = DEDUP_PREF_Title
|
key = SCANLATOR_PREF
|
||||||
entries = arrayOf("Mostrar todos los scanlators", "Mostrar solo un scanlator")
|
title = SCANLATOR_PREF_TITLE
|
||||||
entryValues = arrayOf("all", "one")
|
summary = SCANLATOR_PREF_SUMMARY
|
||||||
summary = "%s"
|
setDefaultValue(SCANLATOR_PREF_DEFAULT_VALUE)
|
||||||
|
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
val selected = newValue as String
|
val checkValue = newValue as Boolean
|
||||||
val index = this.findIndexOfValue(selected)
|
preferences.edit().putBoolean(SCANLATOR_PREF, checkValue).commit()
|
||||||
val entry = entryValues[index] as String
|
|
||||||
preferences.edit().putString(DEDUP_PREF, entry).commit()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val pageMethod = androidx.preference.ListPreference(screen.context).apply {
|
val pageMethodPref = androidx.preference.ListPreference(screen.context).apply {
|
||||||
key = PAGEGET_PREF_Title
|
key = PAGE_METHOD_PREF
|
||||||
title = PAGEGET_PREF_Title
|
title = PAGE_METHOD_PREF_TITLE
|
||||||
entries = arrayOf("Cascada (recomendado)", "Paginado")
|
entries = arrayOf("Cascada", "Páginado")
|
||||||
entryValues = arrayOf("cascade", "paginated")
|
entryValues = arrayOf("cascade", "paginated")
|
||||||
summary = "%s"
|
summary = PAGE_METHOD_PREF_SUMMARY
|
||||||
|
setDefaultValue(PAGE_METHOD_PREF_DEFAULT_VALUE)
|
||||||
|
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
val selected = newValue as String
|
try {
|
||||||
val index = this.findIndexOfValue(selected)
|
val setting = preferences.edit().putString(PAGE_METHOD_PREF, newValue as String).commit()
|
||||||
val entry = entryValues[index] as String
|
setting
|
||||||
preferences.edit().putString(PAGEGET_PREF, entry).commit()
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
screen.addPreference(deduppref)
|
// Rate limit
|
||||||
screen.addPreference(pageMethod)
|
val apiRateLimitPreference = androidx.preference.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)
|
||||||
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
|
try {
|
||||||
|
val setting = preferences.edit().putString(WEB_RATELIMIT_PREF, newValue as String).commit()
|
||||||
|
setting
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val imgCDNRateLimitPreference = androidx.preference.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)
|
||||||
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
|
try {
|
||||||
|
val setting = preferences.edit().putString(IMAGE_CDN_RATELIMIT_PREF, newValue as String).commit()
|
||||||
|
setting
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
screen.addPreference(scanlatorPref)
|
||||||
|
screen.addPreference(pageMethodPref)
|
||||||
|
screen.addPreference(apiRateLimitPreference)
|
||||||
|
screen.addPreference(imgCDNRateLimitPreference)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||||
val deduppref = ListPreference(screen.context).apply {
|
|
||||||
key = DEDUP_PREF_Title
|
val scanlatorPref = CheckBoxPreference(screen.context).apply {
|
||||||
title = DEDUP_PREF_Title
|
key = SCANLATOR_PREF
|
||||||
entries = arrayOf("Mostrar todos los scanlators", "Mostrar solo un scanlator")
|
title = SCANLATOR_PREF_TITLE
|
||||||
entryValues = arrayOf("all", "one")
|
summary = SCANLATOR_PREF_SUMMARY
|
||||||
summary = "%s"
|
setDefaultValue(SCANLATOR_PREF_DEFAULT_VALUE)
|
||||||
|
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
val selected = newValue as String
|
val checkValue = newValue as Boolean
|
||||||
val index = this.findIndexOfValue(selected)
|
preferences.edit().putBoolean(SCANLATOR_PREF, checkValue).commit()
|
||||||
val entry = entryValues[index] as String
|
|
||||||
preferences.edit().putString(DEDUP_PREF, entry).commit()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val pageMethod = ListPreference(screen.context).apply {
|
val pageMethodPref = ListPreference(screen.context).apply {
|
||||||
key = PAGEGET_PREF_Title
|
key = PAGE_METHOD_PREF
|
||||||
title = PAGEGET_PREF_Title
|
title = PAGE_METHOD_PREF_TITLE
|
||||||
entries = arrayOf("Cascada (recomendado)", "Paginado")
|
entries = arrayOf("Cascada", "Páginado")
|
||||||
entryValues = arrayOf("cascade", "paginated")
|
entryValues = arrayOf("cascade", "paginated")
|
||||||
summary = "%s"
|
summary = PAGE_METHOD_PREF_SUMMARY
|
||||||
|
setDefaultValue(PAGE_METHOD_PREF_DEFAULT_VALUE)
|
||||||
|
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
val selected = newValue as String
|
try {
|
||||||
val index = this.findIndexOfValue(selected)
|
val setting = preferences.edit().putString(PAGE_METHOD_PREF, newValue as String).commit()
|
||||||
val entry = entryValues[index] as String
|
setting
|
||||||
preferences.edit().putString(PAGEGET_PREF, entry).commit()
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
screen.addPreference(deduppref)
|
// Rate limit
|
||||||
screen.addPreference(pageMethod)
|
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)
|
||||||
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
|
try {
|
||||||
|
val setting = preferences.edit().putString(WEB_RATELIMIT_PREF, newValue as String).commit()
|
||||||
|
setting
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
|
try {
|
||||||
|
val setting = preferences.edit().putString(IMAGE_CDN_RATELIMIT_PREF, newValue as String).commit()
|
||||||
|
setting
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
screen.addPreference(scanlatorPref)
|
||||||
|
screen.addPreference(pageMethodPref)
|
||||||
|
screen.addPreference(apiRateLimitPreference)
|
||||||
|
screen.addPreference(imgCDNRateLimitPreference)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getduppref() = preferences.getString(DEDUP_PREF, "all")
|
private fun getScanlatorPref(): Boolean = preferences.getBoolean(SCANLATOR_PREF, SCANLATOR_PREF_DEFAULT_VALUE)
|
||||||
|
|
||||||
private fun getPageMethod() = preferences.getString(PAGEGET_PREF, "cascade")
|
private fun getPageMethodPref() = preferences.getString(PAGE_METHOD_PREF, PAGE_METHOD_PREF_DEFAULT_VALUE)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val DEDUP_PREF_Title = "Preferencias de scanlator"
|
private const val SCANLATOR_PREF = "scanlatorPref"
|
||||||
private const val DEDUP_PREF = "deduppref"
|
private const val SCANLATOR_PREF_TITLE = "Mostrar todos los scanlator"
|
||||||
private const val PAGEGET_PREF_Title = "Método para la descarga de imágenes"
|
private const val SCANLATOR_PREF_SUMMARY = "Se mostraran capítulos repetidos pero con diferentes Scanlators"
|
||||||
private const val PAGEGET_PREF = "pagemethodpref"
|
private const val SCANLATOR_PREF_DEFAULT_VALUE = true
|
||||||
|
|
||||||
|
private const val PAGE_METHOD_PREF = "pageMethodPref"
|
||||||
|
private const val PAGE_METHOD_PREF_TITLE = "Método para descargar imágenes"
|
||||||
|
private const val PAGE_METHOD_PREF_SUMMARY = "Previene ser banneado por el servidor cuando se usa la configuración \"Cascada\" ya que esta reduce la cantidad de solicitudes.\nPuedes usar \"Páginado\" cuando las imágenes no carguen usando \"Cascada\".\nConfiguración actual: %s"
|
||||||
|
private const val PAGE_METHOD_PREF_DEFAULT_VALUE = "cascade"
|
||||||
|
|
||||||
|
private const val WEB_RATELIMIT_PREF = "webRatelimitPreference"
|
||||||
|
// Ratelimit permits per second for main website
|
||||||
|
private const val WEB_RATELIMIT_PREF_TITLE = "Ratelimit por minuto para el sitio web"
|
||||||
|
// This value affects network request amount to TMO url. Lower this value may reduce the chance to get HTTP 429 error, but loading speed will be slower too. Tachiyomi restart required. \nCurrent value: %s
|
||||||
|
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 Tachiyomi. \nValor actual: %s"
|
||||||
|
private const val WEB_RATELIMIT_PREF_DEFAULT_VALUE = "10"
|
||||||
|
|
||||||
|
private const val IMAGE_CDN_RATELIMIT_PREF = "imgCDNRatelimitPreference"
|
||||||
|
// Ratelimit permits per second for image CDN
|
||||||
|
private const val IMAGE_CDN_RATELIMIT_PREF_TITLE = "Ratelimit por minuto para descarga de imágenes"
|
||||||
|
// This value affects network request amount for loading image. Lower this value may reduce the chance to get error when loading image, but loading speed will be slower too. Tachiyomi restart required. \nCurrent value: %s
|
||||||
|
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 Tachiyomi. \nValor actual: %s"
|
||||||
|
private const val IMAGE_CDN_RATELIMIT_PREF_DEFAULT_VALUE = "10"
|
||||||
|
|
||||||
|
private val ENTRIES_ARRAY = (1..10).map { i -> i.toString() }.toTypedArray()
|
||||||
|
|
||||||
const val PREFIX_ID_SEARCH = "id:"
|
const val PREFIX_ID_SEARCH = "id:"
|
||||||
const val MANGA_URL_CHUNK = "gotobook"
|
const val MANGA_URL_CHUNK = "gotobook"
|
||||||
|
@ -5,7 +5,7 @@ ext {
|
|||||||
extName = 'TMOHentai'
|
extName = 'TMOHentai'
|
||||||
pkgNameSuffix = 'es.tmohentai'
|
pkgNameSuffix = 'es.tmohentai'
|
||||||
extClass = '.TMOHentai'
|
extClass = '.TMOHentai'
|
||||||
extVersionCode = 4
|
extVersionCode = 5
|
||||||
libVersion = '1.2'
|
libVersion = '1.2'
|
||||||
containsNsfw = true
|
containsNsfw = true
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,13 @@
|
|||||||
package eu.kanade.tachiyomi.extension.es.tmohentai
|
package eu.kanade.tachiyomi.extension.es.tmohentai
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import android.content.SharedPreferences
|
||||||
|
import android.support.v7.preference.ListPreference
|
||||||
|
import android.support.v7.preference.PreferenceScreen
|
||||||
import eu.kanade.tachiyomi.annotations.Nsfw
|
import eu.kanade.tachiyomi.annotations.Nsfw
|
||||||
import eu.kanade.tachiyomi.network.GET
|
import eu.kanade.tachiyomi.network.GET
|
||||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||||
|
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
|
||||||
import eu.kanade.tachiyomi.source.model.MangasPage
|
import eu.kanade.tachiyomi.source.model.MangasPage
|
||||||
@ -15,9 +20,11 @@ import okhttp3.Request
|
|||||||
import org.jsoup.nodes.Document
|
import org.jsoup.nodes.Document
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import rx.Observable
|
import rx.Observable
|
||||||
|
import uy.kohesive.injekt.Injekt
|
||||||
|
import uy.kohesive.injekt.api.get
|
||||||
|
|
||||||
@Nsfw
|
@Nsfw
|
||||||
class TMOHentai : ParsedHttpSource() {
|
class TMOHentai : ConfigurableSource, ParsedHttpSource() {
|
||||||
|
|
||||||
override val name = "TMOHentai"
|
override val name = "TMOHentai"
|
||||||
|
|
||||||
@ -27,6 +34,10 @@ class TMOHentai : ParsedHttpSource() {
|
|||||||
|
|
||||||
override val supportsLatest = true
|
override val supportsLatest = true
|
||||||
|
|
||||||
|
private val preferences: SharedPreferences by lazy {
|
||||||
|
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||||
|
}
|
||||||
|
|
||||||
override fun popularMangaRequest(page: Int) = GET("$baseUrl/section/all?view=list&page=$page&order=popularity&order-dir=desc&search[searchText]=&search[searchBy]=name&type=all", headers)
|
override fun popularMangaRequest(page: Int) = GET("$baseUrl/section/all?view=list&page=$page&order=popularity&order-dir=desc&search[searchText]=&search[searchBy]=name&type=all", headers)
|
||||||
|
|
||||||
override fun popularMangaSelector() = "table > tbody > tr[data-toggle=popover]"
|
override fun popularMangaSelector() = "table > tbody > tr[data-toggle=popover]"
|
||||||
@ -71,19 +82,47 @@ class TMOHentai : ParsedHttpSource() {
|
|||||||
|
|
||||||
name = element.select("h3.truncate").text()
|
name = element.select("h3.truncate").text()
|
||||||
scanlator = parsedInformation.substringAfter("By").substringBefore("Language").trim()
|
scanlator = parsedInformation.substringAfter("By").substringBefore("Language").trim()
|
||||||
setUrlWithoutDomain(element.select("a.pull-right.btn.btn-primary").attr("href"))
|
|
||||||
|
var currentUrl = element.select("a.pull-right.btn.btn-primary").attr("href")
|
||||||
|
|
||||||
|
if (currentUrl.contains("/1")) {
|
||||||
|
currentUrl = currentUrl.substringBeforeLast("/")
|
||||||
|
}
|
||||||
|
|
||||||
|
setUrlWithoutDomain(currentUrl)
|
||||||
// date_upload = no date in the web
|
// date_upload = no date in the web
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun pageListRequest(chapter: SChapter) = GET(baseUrl + chapter.url.substringBefore("/paginated") + "/cascade", headers) // "/cascade" to get all images
|
// "/cascade" to get all images
|
||||||
|
override fun pageListRequest(chapter: SChapter): Request {
|
||||||
|
val currentUrl = chapter.url
|
||||||
|
val newUrl = if (getPageMethodPref() == "cascade" && currentUrl.contains("paginated")) {
|
||||||
|
currentUrl.substringBefore("paginated") + "cascade"
|
||||||
|
} else if (getPageMethodPref() == "paginated" && currentUrl.contains("cascade")) {
|
||||||
|
currentUrl.substringBefore("cascade") + "paginated"
|
||||||
|
} else currentUrl
|
||||||
|
|
||||||
|
return GET("$baseUrl$newUrl", headers)
|
||||||
|
}
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> = mutableListOf<Page>().apply {
|
override fun pageListParse(document: Document): List<Page> = mutableListOf<Page>().apply {
|
||||||
document.select("div#content-images > div.row > div.col-xs-12.text-center > img.content-image")?.forEach {
|
if (getPageMethodPref() == "cascade") {
|
||||||
add(Page(size, "", baseUrl + it.attr("data-original")))
|
document.select("div#content-images img.content-image")?.forEach {
|
||||||
|
add(Page(size, "", it.attr("data-original")))
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val pageList = document.select("select#select-page").first().select("option").map { it.attr("value").toInt() }
|
||||||
|
val url = document.baseUri()
|
||||||
|
|
||||||
|
pageList.forEach {
|
||||||
|
add(Page(it, "$url/$it"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun imageUrlParse(document: Document) = throw UnsupportedOperationException("Not used")
|
override fun imageUrlParse(document: Document) = document.select("div#content-images img.content-image").attr("data-original")
|
||||||
|
|
||||||
|
override fun imageRequest(page: Page) = GET("$baseUrl${page.imageUrl!!}", headers)
|
||||||
|
|
||||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||||
val url = HttpUrl.parse("$baseUrl/section/all?view=list")!!.newBuilder()
|
val url = HttpUrl.parse("$baseUrl/section/all?view=list")!!.newBuilder()
|
||||||
@ -193,9 +232,13 @@ class TMOHentai : ParsedHttpSource() {
|
|||||||
Selection(2, false)
|
Selection(2, false)
|
||||||
)
|
)
|
||||||
|
|
||||||
// Array.from(document.querySelectorAll('#advancedSearch .list-group .list-group-item'))
|
/**
|
||||||
// .map(a => `Genre("${a.querySelector('span').innerText.replace(' ', '')}", "${a.querySelector('input').value}")`).join(',\n')
|
* Last check: 17/02/2021
|
||||||
// https://tmohentai.com/section/hentai
|
* https://tmohentai.com/section/hentai
|
||||||
|
*
|
||||||
|
* Array.from(document.querySelectorAll('#advancedSearch .list-group .list-group-item'))
|
||||||
|
* .map(a => `Genre("${a.querySelector('span').innerText.replace(' ', '')}", "${a.querySelector('input').value}")`).join(',\n')
|
||||||
|
*/
|
||||||
private fun getGenreList() = listOf(
|
private fun getGenreList() = listOf(
|
||||||
Genre("Romance", "1"),
|
Genre("Romance", "1"),
|
||||||
Genre("Fantasy", "2"),
|
Genre("Fantasy", "2"),
|
||||||
@ -245,7 +288,62 @@ class TMOHentai : ParsedHttpSource() {
|
|||||||
Genre("Yandere", "46")
|
Genre("Yandere", "46")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
override fun setupPreferenceScreen(screen: androidx.preference.PreferenceScreen) {
|
||||||
|
val pageMethodPref = androidx.preference.ListPreference(screen.context).apply {
|
||||||
|
key = PAGE_METHOD_PREF
|
||||||
|
title = PAGE_METHOD_PREF_TITLE
|
||||||
|
entries = arrayOf("Cascada", "Páginado")
|
||||||
|
entryValues = arrayOf("cascade", "paginated")
|
||||||
|
summary = PAGE_METHOD_PREF_SUMMARY
|
||||||
|
setDefaultValue(PAGE_METHOD_PREF_DEFAULT_VALUE)
|
||||||
|
|
||||||
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
|
try {
|
||||||
|
val setting = preferences.edit().putString(PAGE_METHOD_PREF, newValue as String).commit()
|
||||||
|
setting
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
screen.addPreference(pageMethodPref)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||||
|
val pageMethodPref = ListPreference(screen.context).apply {
|
||||||
|
key = PAGE_METHOD_PREF
|
||||||
|
title = PAGE_METHOD_PREF_TITLE
|
||||||
|
entries = arrayOf("Cascada", "Páginado")
|
||||||
|
entryValues = arrayOf(PAGE_METHOD_PREF_CASCADE, PAGE_METHOD_PREF_PAGINATED)
|
||||||
|
summary = PAGE_METHOD_PREF_SUMMARY
|
||||||
|
setDefaultValue(PAGE_METHOD_PREF_DEFAULT_VALUE)
|
||||||
|
|
||||||
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
|
try {
|
||||||
|
val setting = preferences.edit().putString(PAGE_METHOD_PREF, newValue as String).commit()
|
||||||
|
setting
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
screen.addPreference(pageMethodPref)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getPageMethodPref() = preferences.getString(PAGE_METHOD_PREF, PAGE_METHOD_PREF_DEFAULT_VALUE)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
private const val PAGE_METHOD_PREF = "pageMethodPref"
|
||||||
|
private const val PAGE_METHOD_PREF_TITLE = "Método de descarga de imágenes"
|
||||||
|
private const val PAGE_METHOD_PREF_SUMMARY = "Puede corregir errores al cargar las imágenes.\nConfiguración actual: %s"
|
||||||
|
private const val PAGE_METHOD_PREF_CASCADE = "cascade"
|
||||||
|
private const val PAGE_METHOD_PREF_PAGINATED = "paginated"
|
||||||
|
private const val PAGE_METHOD_PREF_DEFAULT_VALUE = PAGE_METHOD_PREF_CASCADE
|
||||||
|
|
||||||
const val PREFIX_CONTENTS = "contents"
|
const val PREFIX_CONTENTS = "contents"
|
||||||
const val PREFIX_ID_SEARCH = "id:"
|
const val PREFIX_ID_SEARCH = "id:"
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ ext {
|
|||||||
extName = 'TuMangaOnline'
|
extName = 'TuMangaOnline'
|
||||||
pkgNameSuffix = 'es.tumangaonline'
|
pkgNameSuffix = 'es.tumangaonline'
|
||||||
extClass = '.TuMangaOnline'
|
extClass = '.TuMangaOnline'
|
||||||
extVersionCode = 31
|
extVersionCode = 32
|
||||||
libVersion = '1.2'
|
libVersion = '1.2'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@ package eu.kanade.tachiyomi.extension.es.tumangaonline
|
|||||||
|
|
||||||
import android.app.Application
|
import android.app.Application
|
||||||
import android.content.SharedPreferences
|
import android.content.SharedPreferences
|
||||||
|
import android.support.v7.preference.CheckBoxPreference
|
||||||
import android.support.v7.preference.ListPreference
|
import android.support.v7.preference.ListPreference
|
||||||
import android.support.v7.preference.PreferenceScreen
|
import android.support.v7.preference.PreferenceScreen
|
||||||
import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor
|
import eu.kanade.tachiyomi.lib.ratelimit.SpecificHostRateLimitInterceptor
|
||||||
@ -16,7 +17,6 @@ import eu.kanade.tachiyomi.source.model.SChapter
|
|||||||
import eu.kanade.tachiyomi.source.model.SManga
|
import eu.kanade.tachiyomi.source.model.SManga
|
||||||
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
||||||
import eu.kanade.tachiyomi.util.asJsoup
|
import eu.kanade.tachiyomi.util.asJsoup
|
||||||
import okhttp3.Headers
|
|
||||||
import okhttp3.HttpUrl
|
import okhttp3.HttpUrl
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
@ -35,28 +35,37 @@ class TuMangaOnline : ConfigurableSource, ParsedHttpSource() {
|
|||||||
|
|
||||||
override val baseUrl = "https://lectortmo.com"
|
override val baseUrl = "https://lectortmo.com"
|
||||||
|
|
||||||
val baseurl = HttpUrl.parse(baseUrl)!!
|
|
||||||
|
|
||||||
override val lang = "es"
|
override val lang = "es"
|
||||||
|
|
||||||
override val supportsLatest = true
|
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"
|
private val imageCDNUrl = "https://img1.japanreader.com"
|
||||||
|
|
||||||
private val rateLimitInterceptor = SpecificHostRateLimitInterceptor(baseurl, 10, 60) // real ratelimit values
|
private val preferences: SharedPreferences by lazy {
|
||||||
|
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||||
override val client: OkHttpClient = network.client.newBuilder()
|
|
||||||
.addNetworkInterceptor(rateLimitInterceptor)
|
|
||||||
.build()
|
|
||||||
|
|
||||||
override fun headersBuilder(): Headers.Builder {
|
|
||||||
return Headers.Builder()
|
|
||||||
.add("User-Agent", userAgent)
|
|
||||||
.add("Referer", "$baseUrl/")
|
|
||||||
.add("Cache-mode", "no-cache")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun popularMangaRequest(page: Int) = GET("$baseUrl/library?order_item=likes_count&order_dir=desc&filter_by=title&_page=1&page=$page", headers)
|
private val webRateLimitInterceptor = SpecificHostRateLimitInterceptor(
|
||||||
|
HttpUrl.parse(baseUrl)!!,
|
||||||
|
preferences.getString(WEB_RATELIMIT_PREF, WEB_RATELIMIT_PREF_DEFAULT_VALUE)!!.toInt(),
|
||||||
|
60
|
||||||
|
)
|
||||||
|
|
||||||
|
private val imageCDNRateLimitInterceptor = SpecificHostRateLimitInterceptor(
|
||||||
|
HttpUrl.parse(imageCDNUrl)!!,
|
||||||
|
preferences.getString(IMAGE_CDN_RATELIMIT_PREF, IMAGE_CDN_RATELIMIT_PREF_DEFAULT_VALUE)!!.toInt(),
|
||||||
|
60
|
||||||
|
)
|
||||||
|
|
||||||
|
override val client: OkHttpClient = network.client.newBuilder()
|
||||||
|
.addNetworkInterceptor(webRateLimitInterceptor)
|
||||||
|
.addNetworkInterceptor(imageCDNRateLimitInterceptor)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
// Marks erotic content as false and excludes: Ecchi(6), GirlsLove(17), BoysLove(18) and Harem(19) genders
|
||||||
|
private val getSFWUrlPart = if (getSFWModePref()) "&exclude_genders%5B%5D=6&exclude_genders%5B%5D=17&exclude_genders%5B%5D=18&exclude_genders%5B%5D=19&erotic=false" else ""
|
||||||
|
|
||||||
|
override fun popularMangaRequest(page: Int) = GET("$baseUrl/library?order_item=likes_count&order_dir=desc&filter_by=title$getSFWUrlPart&_page=1&page=$page", headers)
|
||||||
|
|
||||||
override fun popularMangaNextPageSelector() = "a.page-link"
|
override fun popularMangaNextPageSelector() = "a.page-link"
|
||||||
|
|
||||||
@ -70,7 +79,7 @@ class TuMangaOnline : ConfigurableSource, ParsedHttpSource() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/library?order_item=creation&order_dir=desc&filter_by=title&_page=1&page=$page", headers)
|
override fun latestUpdatesRequest(page: Int) = GET("$baseUrl/library?order_item=creation&order_dir=desc&filter_by=title$getSFWUrlPart&_page=1&page=$page", headers)
|
||||||
|
|
||||||
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
|
override fun latestUpdatesNextPageSelector() = popularMangaNextPageSelector()
|
||||||
|
|
||||||
@ -80,11 +89,15 @@ class TuMangaOnline : ConfigurableSource, ParsedHttpSource() {
|
|||||||
|
|
||||||
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
override fun searchMangaRequest(page: Int, query: String, filters: FilterList): Request {
|
||||||
val url = HttpUrl.parse("$baseUrl/library")!!.newBuilder()
|
val url = HttpUrl.parse("$baseUrl/library")!!.newBuilder()
|
||||||
|
|
||||||
url.addQueryParameter("title", query)
|
url.addQueryParameter("title", query)
|
||||||
|
if (getSFWModePref()) {
|
||||||
|
SFW_MODE_PREF_EXCLUDE_GENDERS.forEach { gender ->
|
||||||
|
url.addQueryParameter("exclude_genders[]", gender)
|
||||||
|
}
|
||||||
|
url.addQueryParameter("erotic", "false")
|
||||||
|
}
|
||||||
url.addQueryParameter("page", page.toString())
|
url.addQueryParameter("page", page.toString())
|
||||||
url.addQueryParameter("_page", "1") // Extra Query to Prevent Scrapping aka without it = 403
|
url.addQueryParameter("_page", "1") // Extra Query to Prevent Scrapping aka without it = 403
|
||||||
|
|
||||||
filters.forEach { filter ->
|
filters.forEach { filter ->
|
||||||
when (filter) {
|
when (filter) {
|
||||||
is Types -> {
|
is Types -> {
|
||||||
@ -93,6 +106,12 @@ class TuMangaOnline : ConfigurableSource, ParsedHttpSource() {
|
|||||||
is Demography -> {
|
is Demography -> {
|
||||||
url.addQueryParameter("demography", filter.toUriPart())
|
url.addQueryParameter("demography", filter.toUriPart())
|
||||||
}
|
}
|
||||||
|
is Status -> {
|
||||||
|
url.addQueryParameter("status", filter.toUriPart())
|
||||||
|
}
|
||||||
|
is TranslationStatus -> {
|
||||||
|
url.addQueryParameter("translation_status", filter.toUriPart())
|
||||||
|
}
|
||||||
is FilterBy -> {
|
is FilterBy -> {
|
||||||
url.addQueryParameter("filter_by", filter.toUriPart())
|
url.addQueryParameter("filter_by", filter.toUriPart())
|
||||||
}
|
}
|
||||||
@ -105,93 +124,58 @@ class TuMangaOnline : ConfigurableSource, ParsedHttpSource() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
is WebcomicFilter -> {
|
is ContentTypeList -> {
|
||||||
url.addQueryParameter(
|
filter.state.forEach { content ->
|
||||||
"webcomic",
|
// If (SFW mode is not enabled) OR (SFW mode is enabled AND filter != erotic) -> Apply filter
|
||||||
when (filter.state) {
|
// else -> ignore filter
|
||||||
Filter.TriState.STATE_INCLUDE -> "true"
|
if (!getSFWModePref() || (getSFWModePref() && content.id != "erotic")) {
|
||||||
Filter.TriState.STATE_EXCLUDE -> "false"
|
when (content.state) {
|
||||||
else -> ""
|
Filter.TriState.STATE_IGNORE -> url.addQueryParameter(content.id, "")
|
||||||
|
Filter.TriState.STATE_INCLUDE -> url.addQueryParameter(content.id, "true")
|
||||||
|
Filter.TriState.STATE_EXCLUDE -> url.addQueryParameter(content.id, "false")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
)
|
}
|
||||||
}
|
|
||||||
is FourKomaFilter -> {
|
|
||||||
url.addQueryParameter(
|
|
||||||
"yonkoma",
|
|
||||||
when (filter.state) {
|
|
||||||
Filter.TriState.STATE_INCLUDE -> "true"
|
|
||||||
Filter.TriState.STATE_EXCLUDE -> "false"
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
is AmateurFilter -> {
|
|
||||||
url.addQueryParameter(
|
|
||||||
"amateur",
|
|
||||||
when (filter.state) {
|
|
||||||
Filter.TriState.STATE_INCLUDE -> "true"
|
|
||||||
Filter.TriState.STATE_EXCLUDE -> "false"
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
is EroticFilter -> {
|
|
||||||
url.addQueryParameter(
|
|
||||||
"erotic",
|
|
||||||
when (filter.state) {
|
|
||||||
Filter.TriState.STATE_INCLUDE -> "true"
|
|
||||||
Filter.TriState.STATE_EXCLUDE -> "false"
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
is GenreList -> {
|
is GenreList -> {
|
||||||
filter.state
|
filter.state.forEach { genre ->
|
||||||
.filter { genre -> genre.state }
|
when (genre.state) {
|
||||||
.forEach { genre -> url.addQueryParameter("genders[]", genre.id) }
|
Filter.TriState.STATE_INCLUDE -> url.addQueryParameter("exclude_genders[]", genre.id)
|
||||||
|
Filter.TriState.STATE_EXCLUDE -> url.addQueryParameter("genders[]", genre.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return GET(url.build().toString(), headers)
|
return GET(url.build().toString(), headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun searchMangaSelector() = popularMangaSelector()
|
override fun searchMangaSelector() = popularMangaSelector()
|
||||||
|
|
||||||
override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
|
override fun searchMangaNextPageSelector() = popularMangaNextPageSelector()
|
||||||
|
|
||||||
override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element)
|
override fun searchMangaFromElement(element: Element): SManga = popularMangaFromElement(element)
|
||||||
|
|
||||||
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
override fun mangaDetailsParse(document: Document) = SManga.create().apply {
|
||||||
title = document.select("h2.element-subtitle").text()
|
title = document.select("h2.element-subtitle").text()
|
||||||
document.select("h5.card-title").let {
|
document.select("h5.card-title").let {
|
||||||
author = it?.first()?.attr("title")?.substringAfter(", ")
|
author = it?.first()?.attr("title")?.substringAfter(", ")
|
||||||
artist = it?.last()?.attr("title")?.substringAfter(", ")
|
artist = it?.last()?.attr("title")?.substringAfter(", ")
|
||||||
}
|
}
|
||||||
|
|
||||||
genre = document.select("a.py-2").joinToString(", ") {
|
genre = document.select("a.py-2").joinToString(", ") {
|
||||||
it.text()
|
it.text()
|
||||||
}
|
}
|
||||||
|
|
||||||
description = document.select("p.element-description")?.text()
|
description = document.select("p.element-description")?.text()
|
||||||
status = parseStatus(document.select("span.book-status")?.text().orEmpty())
|
status = parseStatus(document.select("span.book-status")?.text().orEmpty())
|
||||||
thumbnail_url = document.select(".book-thumbnail").attr("src")
|
thumbnail_url = document.select(".book-thumbnail").attr("src")
|
||||||
}
|
}
|
||||||
|
|
||||||
private 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
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun chapterListParse(response: Response): List<SChapter> {
|
override fun chapterListParse(response: Response): List<SChapter> {
|
||||||
val document = response.asJsoup()
|
val document = response.asJsoup()
|
||||||
|
|
||||||
// One-shot
|
// One-shot
|
||||||
if (document.select("div.chapters").isEmpty()) {
|
if (document.select("div.chapters").isEmpty()) {
|
||||||
return document.select(oneShotChapterListSelector()).map { oneShotChapterFromElement(it) }
|
return document.select(oneShotChapterListSelector()).map { oneShotChapterFromElement(it) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Regular list of chapters
|
// Regular list of chapters
|
||||||
val chapters = mutableListOf<SChapter>()
|
val chapters = mutableListOf<SChapter>()
|
||||||
document.select(regularChapterListSelector()).forEach { chapelement ->
|
document.select(regularChapterListSelector()).forEach { chapelement ->
|
||||||
@ -202,22 +186,17 @@ class TuMangaOnline : ConfigurableSource, ParsedHttpSource() {
|
|||||||
.toFloat()
|
.toFloat()
|
||||||
val chaptername = chapelement.select("div.col-10.text-truncate").text()
|
val chaptername = chapelement.select("div.col-10.text-truncate").text()
|
||||||
val scanelement = chapelement.select("ul.chapter-list > li")
|
val scanelement = chapelement.select("ul.chapter-list > li")
|
||||||
val dupselect = getduppref()!!
|
if (getScanlatorPref()) {
|
||||||
if (dupselect == "one") {
|
|
||||||
scanelement.first { chapters.add(regularChapterFromElement(it, chaptername, chapternumber)) }
|
|
||||||
} else {
|
|
||||||
scanelement.forEach { chapters.add(regularChapterFromElement(it, chaptername, chapternumber)) }
|
scanelement.forEach { chapters.add(regularChapterFromElement(it, chaptername, chapternumber)) }
|
||||||
|
} else {
|
||||||
|
scanelement.first { chapters.add(regularChapterFromElement(it, chaptername, chapternumber)) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return chapters
|
return chapters
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun chapterListSelector() = throw UnsupportedOperationException("Not used")
|
override fun chapterListSelector() = throw UnsupportedOperationException("Not used")
|
||||||
|
|
||||||
override fun chapterFromElement(element: Element) = throw UnsupportedOperationException("Not used")
|
override fun chapterFromElement(element: Element) = throw UnsupportedOperationException("Not used")
|
||||||
|
|
||||||
private fun oneShotChapterListSelector() = "div.chapter-list-element > ul.list-group li.list-group-item"
|
private fun oneShotChapterListSelector() = "div.chapter-list-element > ul.list-group li.list-group-item"
|
||||||
|
|
||||||
private fun oneShotChapterFromElement(element: Element) = SChapter.create().apply {
|
private fun oneShotChapterFromElement(element: Element) = SChapter.create().apply {
|
||||||
url = element.select("div.row > .text-right > a").attr("href")
|
url = element.select("div.row > .text-right > a").attr("href")
|
||||||
name = "One Shot"
|
name = "One Shot"
|
||||||
@ -225,9 +204,7 @@ class TuMangaOnline : ConfigurableSource, ParsedHttpSource() {
|
|||||||
date_upload = element.select("span.badge.badge-primary.p-2").first()?.text()?.let { parseChapterDate(it) }
|
date_upload = element.select("span.badge.badge-primary.p-2").first()?.text()?.let { parseChapterDate(it) }
|
||||||
?: 0
|
?: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun regularChapterListSelector() = "div.chapters > ul.list-group li.p-0.list-group-item"
|
private fun regularChapterListSelector() = "div.chapters > ul.list-group li.p-0.list-group-item"
|
||||||
|
|
||||||
private fun regularChapterFromElement(element: Element, chName: String, number: Float) = SChapter.create().apply {
|
private fun regularChapterFromElement(element: Element, chName: String, number: Float) = 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
|
||||||
@ -236,25 +213,20 @@ class TuMangaOnline : ConfigurableSource, ParsedHttpSource() {
|
|||||||
date_upload = element.select("span.badge.badge-primary.p-2").first()?.text()?.let { parseChapterDate(it) }
|
date_upload = element.select("span.badge.badge-primary.p-2").first()?.text()?.let { parseChapterDate(it) }
|
||||||
?: 0
|
?: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun parseChapterDate(date: String): Long = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).parse(date)?.time
|
private fun parseChapterDate(date: String): Long = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault()).parse(date)?.time
|
||||||
?: 0
|
?: 0
|
||||||
|
|
||||||
override fun pageListRequest(chapter: SChapter): Request {
|
override fun pageListRequest(chapter: SChapter): Request {
|
||||||
val currentUrl = client.newCall(GET(chapter.url, headers)).execute().asJsoup().body().baseUri()
|
val currentUrl = client.newCall(GET(chapter.url, headers)).execute().asJsoup().body().baseUri()
|
||||||
|
|
||||||
// Get /cascade instead of /paginate to get all pages at once
|
// Get /cascade instead of /paginate to get all pages at once
|
||||||
val newUrl = if (getPageMethod() == "cascade" && currentUrl.contains("paginated")) {
|
val newUrl = if (getPageMethodPref() == "cascade" && currentUrl.contains("paginated")) {
|
||||||
currentUrl.substringBefore("paginated") + "cascade"
|
currentUrl.substringBefore("paginated") + "cascade"
|
||||||
} else if (getPageMethod() == "paginated" && currentUrl.contains("cascade")) {
|
} else if (getPageMethodPref() == "paginated" && currentUrl.contains("cascade")) {
|
||||||
currentUrl.substringBefore("cascade") + "paginated"
|
currentUrl.substringBefore("cascade") + "paginated"
|
||||||
} else currentUrl
|
} else currentUrl
|
||||||
|
|
||||||
return GET(newUrl, headers)
|
return GET(newUrl, headers)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun pageListParse(document: Document): List<Page> = mutableListOf<Page>().apply {
|
override fun pageListParse(document: Document): List<Page> = mutableListOf<Page>().apply {
|
||||||
if (getPageMethod() == "cascade") {
|
if (getPageMethodPref() == "cascade") {
|
||||||
document.select("div.viewer-container img").forEach {
|
document.select("div.viewer-container img").forEach {
|
||||||
add(
|
add(
|
||||||
Page(
|
Page(
|
||||||
@ -275,8 +247,7 @@ class TuMangaOnline : ConfigurableSource, ParsedHttpSource() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Note: At this moment (15/02/2021) it's necessary to make the image request without headers to prevent 403.
|
||||||
// Note: At this moment (13/07/2020) it's necessary to make the image request without headers to prevent 403.
|
|
||||||
override fun imageRequest(page: Page) = GET(page.imageUrl!!)
|
override fun imageRequest(page: Page) = GET(page.imageUrl!!)
|
||||||
|
|
||||||
override fun imageUrlParse(document: Document): String {
|
override fun imageUrlParse(document: Document): String {
|
||||||
@ -319,6 +290,27 @@ class TuMangaOnline : ConfigurableSource, ParsedHttpSource() {
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private class Status : UriPartFilter(
|
||||||
|
"Filtrar por estado de serie",
|
||||||
|
arrayOf(
|
||||||
|
Pair("Ver todo", ""),
|
||||||
|
Pair("Publicándose", "publishing"),
|
||||||
|
Pair("Finalizado", "ended"),
|
||||||
|
Pair("Cancelado", "cancelled"),
|
||||||
|
Pair("Pausado", "on_hold")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
private class TranslationStatus : UriPartFilter(
|
||||||
|
"Filtrar por estado de traducción",
|
||||||
|
arrayOf(
|
||||||
|
Pair("Ver todo", ""),
|
||||||
|
Pair("Activo", "publishing"),
|
||||||
|
Pair("Finalizado", "ended"),
|
||||||
|
Pair("Abandonado", "cancelled")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
private class Demography : UriPartFilter(
|
private class Demography : UriPartFilter(
|
||||||
"Filtrar por demografía",
|
"Filtrar por demografía",
|
||||||
arrayOf(
|
arrayOf(
|
||||||
@ -332,7 +324,7 @@ class TuMangaOnline : ConfigurableSource, ParsedHttpSource() {
|
|||||||
)
|
)
|
||||||
|
|
||||||
private class FilterBy : UriPartFilter(
|
private class FilterBy : UriPartFilter(
|
||||||
"Campo de orden",
|
"Filtrar por",
|
||||||
arrayOf(
|
arrayOf(
|
||||||
Pair("Título", "title"),
|
Pair("Título", "title"),
|
||||||
Pair("Autor", "author"),
|
Pair("Autor", "author"),
|
||||||
@ -346,36 +338,38 @@ class TuMangaOnline : ConfigurableSource, ParsedHttpSource() {
|
|||||||
Selection(0, false)
|
Selection(0, false)
|
||||||
)
|
)
|
||||||
|
|
||||||
private class WebcomicFilter : Filter.TriState("Webcomic")
|
private class ContentType(name: String, val id: String) : Filter.TriState(name)
|
||||||
|
|
||||||
private class FourKomaFilter : Filter.TriState("Yonkoma")
|
private class ContentTypeList(content: List<ContentType>) : Filter.Group<ContentType>("Filtrar por tipo de contenido", content)
|
||||||
|
|
||||||
private class AmateurFilter : Filter.TriState("Amateur")
|
private class Genre(name: String, val id: String) : Filter.TriState(name)
|
||||||
|
|
||||||
private class EroticFilter : Filter.TriState("Erótico")
|
|
||||||
|
|
||||||
private class Genre(name: String, val id: String) : Filter.CheckBox(name)
|
|
||||||
|
|
||||||
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Filtrar por géneros", genres)
|
private class GenreList(genres: List<Genre>) : Filter.Group<Genre>("Filtrar por géneros", genres)
|
||||||
|
|
||||||
override fun getFilterList() = FilterList(
|
override fun getFilterList() = FilterList(
|
||||||
Types(),
|
Types(),
|
||||||
|
Filter.Separator(),
|
||||||
|
Filter.Header("Ignorado sino se filtra por tipo"),
|
||||||
|
Status(),
|
||||||
|
Filter.Separator(),
|
||||||
|
Filter.Header("Ignorado sino se filtra por tipo"),
|
||||||
|
TranslationStatus(),
|
||||||
|
Filter.Separator(),
|
||||||
Demography(),
|
Demography(),
|
||||||
Filter.Separator(),
|
Filter.Separator(),
|
||||||
FilterBy(),
|
FilterBy(),
|
||||||
|
Filter.Separator(),
|
||||||
SortBy(),
|
SortBy(),
|
||||||
Filter.Separator(),
|
Filter.Separator(),
|
||||||
WebcomicFilter(),
|
ContentTypeList(getContentTypeList()),
|
||||||
FourKomaFilter(),
|
Filter.Separator(),
|
||||||
AmateurFilter(),
|
|
||||||
EroticFilter(),
|
|
||||||
GenreList(getGenreList())
|
GenreList(getGenreList())
|
||||||
)
|
)
|
||||||
|
|
||||||
// Array.from(document.querySelectorAll('#books-genders .col-auto .custom-control'))
|
// Array.from(document.querySelectorAll('#books-genders .col-auto .custom-control'))
|
||||||
// .map(a => `Genre("${a.querySelector('label').innerText}", "${a.querySelector('input').value}")`).join(',\n')
|
// .map(a => `Genre("${a.querySelector('label').innerText}", "${a.querySelector('input').value}")`).join(',\n')
|
||||||
// on https://tumangaonline.me/library
|
// on https://lectortmo.com/library
|
||||||
// Last revision 13/07/2020
|
// Last revision 15/02/2021
|
||||||
private fun getGenreList() = listOf(
|
private fun getGenreList() = listOf(
|
||||||
Genre("Acción", "1"),
|
Genre("Acción", "1"),
|
||||||
Genre("Aventura", "2"),
|
Genre("Aventura", "2"),
|
||||||
@ -427,94 +421,238 @@ class TuMangaOnline : ConfigurableSource, ParsedHttpSource() {
|
|||||||
Genre("Oeste", "48")
|
Genre("Oeste", "48")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
private fun getContentTypeList() = listOf(
|
||||||
|
ContentType("Webcomic", "webcomic"),
|
||||||
|
ContentType("Yonkoma", "yonkoma"),
|
||||||
|
ContentType("Amateur", "amateur"),
|
||||||
|
ContentType("Erótico", "erotic")
|
||||||
|
)
|
||||||
|
|
||||||
private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) :
|
private open class UriPartFilter(displayName: String, val vals: Array<Pair<String, String>>) :
|
||||||
Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
|
Filter.Select<String>(displayName, vals.map { it.first }.toTypedArray()) {
|
||||||
fun toUriPart() = vals[state].second
|
fun toUriPart() = vals[state].second
|
||||||
}
|
}
|
||||||
|
|
||||||
private val preferences: SharedPreferences by lazy {
|
|
||||||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun setupPreferenceScreen(screen: androidx.preference.PreferenceScreen) {
|
override fun setupPreferenceScreen(screen: androidx.preference.PreferenceScreen) {
|
||||||
val deduppref = androidx.preference.ListPreference(screen.context).apply {
|
|
||||||
key = DEDUP_PREF_Title
|
val SFWModePref = androidx.preference.CheckBoxPreference(screen.context).apply {
|
||||||
title = DEDUP_PREF_Title
|
key = SFW_MODE_PREF
|
||||||
entries = arrayOf("Mostrar todos los scanlators", "Mostrar solo un scanlator")
|
title = SFW_MODE_PREF_TITLE
|
||||||
entryValues = arrayOf("all", "one")
|
summary = SFW_MODE_PREF_SUMMARY
|
||||||
summary = "%s"
|
setDefaultValue(SFW_MODE_PREF_DEFAULT_VALUE)
|
||||||
|
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
val selected = newValue as String
|
val checkValue = newValue as Boolean
|
||||||
val index = this.findIndexOfValue(selected)
|
preferences.edit().putBoolean(SFW_MODE_PREF, checkValue).commit()
|
||||||
val entry = entryValues[index] as String
|
|
||||||
preferences.edit().putString(DEDUP_PREF, entry).commit()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val pageMethod = androidx.preference.ListPreference(screen.context).apply {
|
val scanlatorPref = androidx.preference.CheckBoxPreference(screen.context).apply {
|
||||||
key = PAGEGET_PREF_Title
|
key = SCANLATOR_PREF
|
||||||
title = PAGEGET_PREF_Title
|
title = SCANLATOR_PREF_TITLE
|
||||||
entries = arrayOf("Cascada (recomendado)", "Paginado")
|
summary = SCANLATOR_PREF_SUMMARY
|
||||||
|
setDefaultValue(SCANLATOR_PREF_DEFAULT_VALUE)
|
||||||
|
|
||||||
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
|
val checkValue = newValue as Boolean
|
||||||
|
preferences.edit().putBoolean(SCANLATOR_PREF, checkValue).commit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val pageMethodPref = androidx.preference.ListPreference(screen.context).apply {
|
||||||
|
key = PAGE_METHOD_PREF
|
||||||
|
title = PAGE_METHOD_PREF_TITLE
|
||||||
|
entries = arrayOf("Cascada", "Páginado")
|
||||||
entryValues = arrayOf("cascade", "paginated")
|
entryValues = arrayOf("cascade", "paginated")
|
||||||
summary = "%s"
|
summary = PAGE_METHOD_PREF_SUMMARY
|
||||||
|
setDefaultValue(PAGE_METHOD_PREF_DEFAULT_VALUE)
|
||||||
|
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
val selected = newValue as String
|
try {
|
||||||
val index = this.findIndexOfValue(selected)
|
val setting = preferences.edit().putString(PAGE_METHOD_PREF, newValue as String).commit()
|
||||||
val entry = entryValues[index] as String
|
setting
|
||||||
preferences.edit().putString(PAGEGET_PREF, entry).commit()
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
screen.addPreference(deduppref)
|
// Rate limit
|
||||||
screen.addPreference(pageMethod)
|
val apiRateLimitPreference = androidx.preference.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)
|
||||||
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
|
try {
|
||||||
|
val setting = preferences.edit().putString(WEB_RATELIMIT_PREF, newValue as String).commit()
|
||||||
|
setting
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val imgCDNRateLimitPreference = androidx.preference.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)
|
||||||
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
|
try {
|
||||||
|
val setting = preferences.edit().putString(IMAGE_CDN_RATELIMIT_PREF, newValue as String).commit()
|
||||||
|
setting
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
screen.addPreference(SFWModePref)
|
||||||
|
screen.addPreference(scanlatorPref)
|
||||||
|
screen.addPreference(pageMethodPref)
|
||||||
|
screen.addPreference(apiRateLimitPreference)
|
||||||
|
screen.addPreference(imgCDNRateLimitPreference)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||||
val deduppref = ListPreference(screen.context).apply {
|
|
||||||
key = DEDUP_PREF_Title
|
val SFWModePref = CheckBoxPreference(screen.context).apply {
|
||||||
title = DEDUP_PREF_Title
|
key = SFW_MODE_PREF
|
||||||
entries = arrayOf("Mostrar todos los scanlators", "Mostrar solo un scanlator")
|
title = SFW_MODE_PREF_TITLE
|
||||||
entryValues = arrayOf("all", "one")
|
summary = SFW_MODE_PREF_SUMMARY
|
||||||
summary = "%s"
|
setDefaultValue(SFW_MODE_PREF_DEFAULT_VALUE)
|
||||||
|
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
val selected = newValue as String
|
val checkValue = newValue as Boolean
|
||||||
val index = this.findIndexOfValue(selected)
|
preferences.edit().putBoolean(SFW_MODE_PREF, checkValue).commit()
|
||||||
val entry = entryValues[index] as String
|
|
||||||
preferences.edit().putString(DEDUP_PREF, entry).commit()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val pageMethod = ListPreference(screen.context).apply {
|
val scanlatorPref = CheckBoxPreference(screen.context).apply {
|
||||||
key = PAGEGET_PREF_Title
|
key = SCANLATOR_PREF
|
||||||
title = PAGEGET_PREF_Title
|
title = SCANLATOR_PREF_TITLE
|
||||||
entries = arrayOf("Cascada (recomendado)", "Paginado")
|
summary = SCANLATOR_PREF_SUMMARY
|
||||||
|
setDefaultValue(SCANLATOR_PREF_DEFAULT_VALUE)
|
||||||
|
|
||||||
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
|
val checkValue = newValue as Boolean
|
||||||
|
preferences.edit().putBoolean(SCANLATOR_PREF, checkValue).commit()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
val pageMethodPref = ListPreference(screen.context).apply {
|
||||||
|
key = PAGE_METHOD_PREF
|
||||||
|
title = PAGE_METHOD_PREF_TITLE
|
||||||
|
entries = arrayOf("Cascada", "Páginado")
|
||||||
entryValues = arrayOf("cascade", "paginated")
|
entryValues = arrayOf("cascade", "paginated")
|
||||||
summary = "%s"
|
summary = PAGE_METHOD_PREF_SUMMARY
|
||||||
|
setDefaultValue(PAGE_METHOD_PREF_DEFAULT_VALUE)
|
||||||
|
|
||||||
setOnPreferenceChangeListener { _, newValue ->
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
val selected = newValue as String
|
try {
|
||||||
val index = this.findIndexOfValue(selected)
|
val setting = preferences.edit().putString(PAGE_METHOD_PREF, newValue as String).commit()
|
||||||
val entry = entryValues[index] as String
|
setting
|
||||||
preferences.edit().putString(PAGEGET_PREF, entry).commit()
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
screen.addPreference(deduppref)
|
// Rate limit
|
||||||
screen.addPreference(pageMethod)
|
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)
|
||||||
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
|
try {
|
||||||
|
val setting = preferences.edit().putString(WEB_RATELIMIT_PREF, newValue as String).commit()
|
||||||
|
setting
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
setOnPreferenceChangeListener { _, newValue ->
|
||||||
|
try {
|
||||||
|
val setting = preferences.edit().putString(IMAGE_CDN_RATELIMIT_PREF, newValue as String).commit()
|
||||||
|
setting
|
||||||
|
} catch (e: Exception) {
|
||||||
|
e.printStackTrace()
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
screen.addPreference(SFWModePref)
|
||||||
|
screen.addPreference(scanlatorPref)
|
||||||
|
screen.addPreference(pageMethodPref)
|
||||||
|
screen.addPreference(apiRateLimitPreference)
|
||||||
|
screen.addPreference(imgCDNRateLimitPreference)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getduppref() = preferences.getString(DEDUP_PREF, "all")
|
private fun getScanlatorPref(): Boolean = preferences.getBoolean(SCANLATOR_PREF, SCANLATOR_PREF_DEFAULT_VALUE)
|
||||||
|
|
||||||
private fun getPageMethod() = preferences.getString(PAGEGET_PREF, "cascade")
|
private fun getSFWModePref(): Boolean = preferences.getBoolean(SFW_MODE_PREF, SFW_MODE_PREF_DEFAULT_VALUE)
|
||||||
|
|
||||||
|
private fun getPageMethodPref() = preferences.getString(PAGE_METHOD_PREF, PAGE_METHOD_PREF_DEFAULT_VALUE)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val DEDUP_PREF_Title = "Preferencias de scanlator"
|
private const val SCANLATOR_PREF = "scanlatorPref"
|
||||||
private const val DEDUP_PREF = "deduppref"
|
private const val SCANLATOR_PREF_TITLE = "Mostrar todos los scanlator"
|
||||||
private const val PAGEGET_PREF_Title = "Método para la descarga de imágenes"
|
private const val SCANLATOR_PREF_SUMMARY = "Se mostraran capítulos repetidos pero con diferentes Scanlators"
|
||||||
private const val PAGEGET_PREF = "pagemethodpref"
|
private const val SCANLATOR_PREF_DEFAULT_VALUE = true
|
||||||
|
|
||||||
|
private const val SFW_MODE_PREF = "SFWModePref"
|
||||||
|
private const val SFW_MODE_PREF_TITLE = "Ocultar contenido NSFW"
|
||||||
|
private const val SFW_MODE_PREF_SUMMARY = "Ocultar el contenido erótico (puede que aún activandolo se sigan mostrando portadas o series NSFW). Ten en cuenta que al activarlo se ignoran filtros al explorar y buscar.\nLos filtros ignorados son: Filtrar por tipo de contenido (Erotico) y el Filtrar por generos: Ecchi, Boys Love, Girls Love y Harem."
|
||||||
|
private const val SFW_MODE_PREF_DEFAULT_VALUE = false
|
||||||
|
private val SFW_MODE_PREF_EXCLUDE_GENDERS = listOf("6", "17", "18", "19")
|
||||||
|
|
||||||
|
private const val PAGE_METHOD_PREF = "pageMethodPref"
|
||||||
|
private const val PAGE_METHOD_PREF_TITLE = "Método para descargar imágenes"
|
||||||
|
private const val PAGE_METHOD_PREF_SUMMARY = "Previene ser banneado por el servidor cuando se usa la configuración \"Cascada\" ya que esta reduce la cantidad de solicitudes.\nPuedes usar \"Páginado\" cuando las imágenes no carguen usando \"Cascada\".\nConfiguración actual: %s"
|
||||||
|
private const val PAGE_METHOD_PREF_DEFAULT_VALUE = "cascade"
|
||||||
|
|
||||||
|
private const val WEB_RATELIMIT_PREF = "webRatelimitPreference"
|
||||||
|
// Ratelimit permits per second for main website
|
||||||
|
private const val WEB_RATELIMIT_PREF_TITLE = "Ratelimit por minuto para el sitio web"
|
||||||
|
// This value affects network request amount to TMO url. Lower this value may reduce the chance to get HTTP 429 error, but loading speed will be slower too. Tachiyomi restart required. \nCurrent value: %s
|
||||||
|
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 Tachiyomi. \nValor actual: %s"
|
||||||
|
private const val WEB_RATELIMIT_PREF_DEFAULT_VALUE = "10"
|
||||||
|
|
||||||
|
private const val IMAGE_CDN_RATELIMIT_PREF = "imgCDNRatelimitPreference"
|
||||||
|
// Ratelimit permits per second for image CDN
|
||||||
|
private const val IMAGE_CDN_RATELIMIT_PREF_TITLE = "Ratelimit por minuto para descarga de imágenes"
|
||||||
|
// This value affects network request amount for loading image. Lower this value may reduce the chance to get error when loading image, but loading speed will be slower too. Tachiyomi restart required. \nCurrent value: %s
|
||||||
|
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 Tachiyomi. \nValor actual: %s"
|
||||||
|
private const val IMAGE_CDN_RATELIMIT_PREF_DEFAULT_VALUE = "10"
|
||||||
|
|
||||||
|
private val ENTRIES_ARRAY = (1..10).map { i -> i.toString() }.toTypedArray()
|
||||||
|
|
||||||
const val PREFIX_LIBRARY = "library"
|
const val PREFIX_LIBRARY = "library"
|
||||||
const val PREFIX_ID_SEARCH = "id:"
|
const val PREFIX_ID_SEARCH = "id:"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user