Random User-Agent Refactor (#17059)
* lib-randomua * NHentai: Random mobile ua * Madara random UA overhaul * MangaThemesia random UA overhaul * MangaHub random UA overhaul * build errors and warnings * remove preference from Constellar * change to singleton object * network.client * fix copy paste and chapter deep link * exit early * use data class and enum options * missing import * suggested changes Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> * re-add empty check to filters * convert to interceptor * update comment Co-authored-by: Alessandro Jean <14254807+alessandrojean@users.noreply.github.com> * update error message * initialize client by lazy * dont check on excluded Filters Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> * newlines * move preference helper function into lib * move preference helper function into lib x2 * move check to lib too * move defaultRandomUserAgentType to constructor * rename the interceptor * organize the interceptor and preference stuff in different files * hide custom ua setting when random ua is enabled * English Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> * catch specific exception Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> * setVisible() fresh stuff * setVisible() fresh stuff * change summary * workaround * Update error message Co-authored-by: Alessandro Jean <14254807+alessandrojean@users.noreply.github.com> * Update comment Co-authored-by: Alessandro Jean <14254807+alessandrojean@users.noreply.github.com> --------- Co-authored-by: AntsyLich <59261191+AntsyLich@users.noreply.github.com> Co-authored-by: Alessandro Jean <14254807+alessandrojean@users.noreply.github.com>
This commit is contained in:
parent
71f69252ad
commit
50b5d33614
|
@ -0,0 +1,23 @@
|
|||
plugins {
|
||||
id("com.android.library")
|
||||
kotlin("android")
|
||||
id("kotlinx-serialization")
|
||||
}
|
||||
|
||||
android {
|
||||
compileSdk = AndroidConfig.compileSdk
|
||||
namespace = "eu.kanade.tachiyomi.lib.randomua"
|
||||
|
||||
defaultConfig {
|
||||
minSdk = AndroidConfig.minSdk
|
||||
targetSdk = AndroidConfig.targetSdk
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compileOnly(libs.bundles.common)
|
||||
}
|
|
@ -0,0 +1,121 @@
|
|||
package eu.kanade.tachiyomi.lib.randomua
|
||||
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.NetworkHelper
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.Json
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Response
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.IOException
|
||||
|
||||
private class RandomUserAgentInterceptor(
|
||||
private val userAgentType: UserAgentType,
|
||||
private val customUA: String?,
|
||||
private val filterInclude: List<String>,
|
||||
private val filterExclude: List<String>,
|
||||
) : Interceptor {
|
||||
|
||||
private var userAgent: String? = null
|
||||
|
||||
private val json: Json by injectLazy()
|
||||
|
||||
private val network: NetworkHelper by injectLazy()
|
||||
|
||||
private val client = network.client
|
||||
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
try {
|
||||
val originalRequest = chain.request()
|
||||
|
||||
val newUserAgent = getUserAgent()
|
||||
?: return chain.proceed(originalRequest)
|
||||
|
||||
val originalHeaders = originalRequest.headers
|
||||
|
||||
val modifiedHeaders = originalHeaders.newBuilder()
|
||||
.set("User-Agent", newUserAgent)
|
||||
.build()
|
||||
|
||||
return chain.proceed(
|
||||
originalRequest.newBuilder()
|
||||
.headers(modifiedHeaders)
|
||||
.build()
|
||||
)
|
||||
} catch (e: Exception) {
|
||||
throw IOException(e.message)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getUserAgent(): String? {
|
||||
if (userAgentType == UserAgentType.OFF) {
|
||||
return customUA?.ifBlank { null }
|
||||
}
|
||||
|
||||
if (!userAgent.isNullOrEmpty()) return userAgent
|
||||
|
||||
val uaResponse = client.newCall(GET(UA_DB_URL)).execute()
|
||||
|
||||
if (!uaResponse.isSuccessful) {
|
||||
uaResponse.close()
|
||||
return null
|
||||
}
|
||||
|
||||
val userAgentList = uaResponse.use { json.decodeFromString<UserAgentList>(it.body.string()) }
|
||||
|
||||
return when (userAgentType) {
|
||||
UserAgentType.DESKTOP -> userAgentList.desktop
|
||||
UserAgentType.MOBILE -> userAgentList.mobile
|
||||
else -> error("Expected UserAgentType.DESKTOP or UserAgentType.MOBILE but got UserAgentType.${userAgentType.name} instead")
|
||||
}
|
||||
.filter {
|
||||
filterInclude.isEmpty() || filterInclude.any { filter ->
|
||||
it.contains(filter, ignoreCase = true)
|
||||
}
|
||||
}
|
||||
.filterNot {
|
||||
filterExclude.any { filter ->
|
||||
it.contains(filter, ignoreCase = true)
|
||||
}
|
||||
}
|
||||
.randomOrNull()
|
||||
.also { userAgent = it }
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val UA_DB_URL = "https://tachiyomiorg.github.io/user-agents/user-agents.json"
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to add a latest random user agent interceptor.
|
||||
* The interceptor will added at the first position in the chain,
|
||||
* so the CloudflareInterceptor in the app will be able to make usage of it.
|
||||
*
|
||||
* @param userAgentType User Agent type one of (DESKTOP, MOBILE, OFF)
|
||||
* @param customUA Optional custom user agent used when userAgentType is OFF
|
||||
* @param filterInclude Filter to only include User Agents containing these strings
|
||||
* @param filterExclude Filter to exclude User Agents containing these strings
|
||||
*/
|
||||
fun OkHttpClient.Builder.setRandomUserAgent(
|
||||
userAgentType: UserAgentType,
|
||||
customUA: String? = null,
|
||||
filterInclude: List<String> = emptyList(),
|
||||
filterExclude: List<String> = emptyList(),
|
||||
) = apply {
|
||||
interceptors().add(0, RandomUserAgentInterceptor(userAgentType, customUA, filterInclude, filterExclude))
|
||||
}
|
||||
|
||||
enum class UserAgentType {
|
||||
MOBILE,
|
||||
DESKTOP,
|
||||
OFF
|
||||
}
|
||||
|
||||
@Serializable
|
||||
private data class UserAgentList(
|
||||
val desktop: List<String>,
|
||||
val mobile: List<String>
|
||||
)
|
|
@ -0,0 +1,83 @@
|
|||
package eu.kanade.tachiyomi.lib.randomua
|
||||
|
||||
import android.content.SharedPreferences
|
||||
import android.widget.Toast
|
||||
import androidx.preference.EditTextPreference
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.PreferenceScreen
|
||||
import okhttp3.Headers
|
||||
|
||||
class RandomUserAgentPreference(
|
||||
private val preferences: SharedPreferences,
|
||||
) {
|
||||
/**
|
||||
* Helper function to return UserAgentType based on SharedPreference value
|
||||
*/
|
||||
fun getPrefUAType(): UserAgentType {
|
||||
return when (preferences.getString(PREF_KEY_RANDOM_UA, "off")) {
|
||||
"mobile" -> UserAgentType.MOBILE
|
||||
"desktop" -> UserAgentType.DESKTOP
|
||||
else -> UserAgentType.OFF
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to return custom UserAgent from SharedPreference
|
||||
*/
|
||||
fun getPrefCustomUA(): String? {
|
||||
return preferences.getString(PREF_KEY_CUSTOM_UA, null)
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to add Random User-Agent settings to SharedPreference
|
||||
*
|
||||
* @param screen, PreferenceScreen from `setupPreferenceScreen`
|
||||
*/
|
||||
fun addPreferenceToScreen(
|
||||
screen: PreferenceScreen,
|
||||
) {
|
||||
val customUA = EditTextPreference(screen.context).apply {
|
||||
key = PREF_KEY_CUSTOM_UA
|
||||
title = TITLE_CUSTOM_UA
|
||||
summary = CUSTOM_UA_SUMMARY
|
||||
setVisible(getPrefUAType() == UserAgentType.OFF)
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
try {
|
||||
Headers.Builder().add("User-Agent", newValue as String).build()
|
||||
true
|
||||
} catch (e: IllegalArgumentException) {
|
||||
Toast.makeText(screen.context, "User Agent invalid:${e.message}", Toast.LENGTH_LONG).show()
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val randomUA = ListPreference(screen.context).apply {
|
||||
key = PREF_KEY_RANDOM_UA
|
||||
title = TITLE_RANDOM_UA
|
||||
entries = RANDOM_UA_ENTRIES
|
||||
entryValues = RANDOM_UA_VALUES
|
||||
summary = "%s"
|
||||
setDefaultValue("off")
|
||||
setOnPreferenceChangeListener { _, newVal ->
|
||||
val showCustomUAPref = newVal as String == "off"
|
||||
customUA.setVisible(showCustomUAPref)
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
screen.addPreference(randomUA)
|
||||
screen.addPreference(customUA)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TITLE_RANDOM_UA = "Random User-Agent (Requires Restart)"
|
||||
const val PREF_KEY_RANDOM_UA = "pref_key_random_ua_"
|
||||
val RANDOM_UA_ENTRIES = arrayOf("OFF", "Desktop", "Mobile")
|
||||
val RANDOM_UA_VALUES = arrayOf("off", "desktop", "mobile")
|
||||
|
||||
const val TITLE_CUSTOM_UA = "Custom User-Agent"
|
||||
const val PREF_KEY_CUSTOM_UA = "pref_key_custom_ua_"
|
||||
const val CUSTOM_UA_SUMMARY = "Leave blank to use application default user-agent. (Requires Restart)"
|
||||
}
|
||||
}
|
|
@ -1,9 +0,0 @@
|
|||
package eu.kanade.tachiyomi.extension.tr.anisamanga
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import okhttp3.Headers
|
||||
|
||||
class AnisaManga : Madara("Anisa Manga", "https://anisamanga.com", "tr") {
|
||||
override fun headersBuilder(): Headers.Builder = super.headersBuilder()
|
||||
.add("Referer", "https://anisamanga.com")
|
||||
}
|
|
@ -14,7 +14,6 @@ import uy.kohesive.injekt.api.get
|
|||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class BokugenTranslation : Madara(
|
||||
"BokugenTranslation",
|
||||
|
@ -23,8 +22,7 @@ class BokugenTranslation : Madara(
|
|||
dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale("es")),
|
||||
) {
|
||||
private var loadWebView = true
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.addInterceptor(uaIntercept)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.addInterceptor { chain ->
|
||||
val request = chain.request()
|
||||
val url = request.url.toString()
|
||||
|
@ -56,8 +54,6 @@ class BokugenTranslation : Madara(
|
|||
}
|
||||
chain.proceed(request)
|
||||
}
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
.rateLimit(1, 1)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
dependencies {
|
||||
implementation(project(':lib-cryptoaes'))
|
||||
}
|
||||
implementation(project(":lib-cryptoaes"))
|
||||
implementation(project(":lib-randomua"))
|
||||
}
|
||||
|
|
|
@ -7,16 +7,12 @@ import okhttp3.OkHttpClient
|
|||
import org.jsoup.nodes.Document
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class Doodmanga : Madara("Doodmanga", "https://www.doodmanga.com", "th", SimpleDateFormat("dd MMMMM yyyy", Locale("th"))) {
|
||||
override val filterNonMangaItems = false
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.addInterceptor(uaIntercept)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.addInterceptor(ScrambledImageInterceptor)
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
override val pageListParseSelector = "div.text-center > p > img, div.text-center > img, div.text-center > script"
|
||||
|
|
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.extension.en.firstkissmanga
|
|||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import okhttp3.Headers
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class FirstKissManga : Madara(
|
||||
|
@ -10,9 +9,7 @@ class FirstKissManga : Madara(
|
|||
"https://1stkissmanga.me",
|
||||
"en",
|
||||
) {
|
||||
override fun headersBuilder(): Headers.Builder = super.headersBuilder().add("Referer", baseUrl)
|
||||
|
||||
override val client = network.cloudflareClient.newBuilder()
|
||||
override val client = super.client.newBuilder()
|
||||
.rateLimit(1, 3, TimeUnit.SECONDS)
|
||||
.build()
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ class FirstKissMangaClub : Madara(
|
|||
"en",
|
||||
) {
|
||||
|
||||
override val client = network.cloudflareClient.newBuilder()
|
||||
override val client = super.client.newBuilder()
|
||||
.rateLimit(1, 3, TimeUnit.SECONDS)
|
||||
.build()
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ class FirstKissMangaLove : Madara(
|
|||
"en",
|
||||
) {
|
||||
|
||||
override val client = network.cloudflareClient.newBuilder()
|
||||
override val client = super.client.newBuilder()
|
||||
.rateLimit(1, 3, TimeUnit.SECONDS)
|
||||
.build()
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ class FirstKissManhua : Madara(
|
|||
SimpleDateFormat("d MMM yyyy", Locale.US),
|
||||
) {
|
||||
|
||||
override val client = network.cloudflareClient.newBuilder()
|
||||
override val client = super.client.newBuilder()
|
||||
.rateLimit(1, 3, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.extension.pt.fleurblanche
|
|||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import okhttp3.Headers
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Response
|
||||
|
@ -25,8 +24,6 @@ class FleurBlanche : Madara(
|
|||
|
||||
override val useNewChapterEndpoint = true
|
||||
|
||||
override fun headersBuilder(): Headers.Builder = Headers.Builder()
|
||||
|
||||
private fun authWarningIntercept(chain: Interceptor.Chain): Response {
|
||||
val response = chain.proceed(chain.request())
|
||||
|
||||
|
|
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.extension.pt.hentaiteca
|
|||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
@ -18,7 +17,4 @@ class HentaiTeca : Madara(
|
|||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(1, 2, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
override fun headersBuilder(): Headers.Builder = Headers.Builder()
|
||||
.add("Referer", "$baseUrl/")
|
||||
}
|
||||
|
|
|
@ -2,7 +2,6 @@ package eu.kanade.tachiyomi.extension.pt.ichirinnohanayuri
|
|||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
import java.io.IOException
|
||||
import java.text.SimpleDateFormat
|
||||
|
@ -30,8 +29,6 @@ class IchirinNoHanaYuri : Madara(
|
|||
}
|
||||
.build()
|
||||
|
||||
override fun headersBuilder(): Headers.Builder = Headers.Builder()
|
||||
|
||||
companion object {
|
||||
private const val BLOCKING_MESSAGE = "O site está bloqueando o Tachiyomi. " +
|
||||
"Migre para outra fonte caso o problema persistir."
|
||||
|
|
|
@ -26,8 +26,6 @@ class Manga18fx : Madara(
|
|||
) {
|
||||
override val id = 3157287889751723714
|
||||
|
||||
override val client = network.client
|
||||
|
||||
override val fetchGenres = false
|
||||
override val sendViewCount = false
|
||||
|
||||
|
|
|
@ -2,14 +2,10 @@ package eu.kanade.tachiyomi.extension.ar.mangastarz
|
|||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import okhttp3.Headers
|
||||
import org.jsoup.nodes.Element
|
||||
|
||||
class MangaStarz : Madara("Manga Starz", "https://mangastarz.com", "ar") {
|
||||
|
||||
override fun headersBuilder(): Headers.Builder = Headers.Builder()
|
||||
.add("Referer", baseUrl)
|
||||
|
||||
override fun popularMangaFromElement(element: Element): SManga {
|
||||
val manga = SManga.create()
|
||||
|
||||
|
|
|
@ -2,12 +2,9 @@ package eu.kanade.tachiyomi.extension.en.manhuaga
|
|||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import okhttp3.OkHttpClient
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class Manhuaga : Madara("Manhuaga", "https://manhuaga.com", "en") {
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.addInterceptor { chain ->
|
||||
val originalRequest = chain.request()
|
||||
chain.proceed(originalRequest).let { response ->
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
package eu.kanade.tachiyomi.extension.en.mixedmanga
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import okhttp3.Headers
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
class MixedManga : Madara("Mixed Manga", "https://mixedmanga.com", "en", SimpleDateFormat("d MMM yyyy", Locale.US)) {
|
||||
override fun headersBuilder(): Headers.Builder = super.headersBuilder().add("Referer", baseUrl)
|
||||
}
|
||||
class MixedManga : Madara("Mixed Manga", "https://mixedmanga.com", "en", SimpleDateFormat("d MMM yyyy", Locale.US))
|
||||
|
|
|
@ -3,13 +3,10 @@ package eu.kanade.tachiyomi.extension.en.shieldmanga
|
|||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import okhttp3.OkHttpClient
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class ShieldManga : Madara("Shield Manga", "https://shieldmanga.io", "en") {
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(1)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -1,13 +1,10 @@
|
|||
package eu.kanade.tachiyomi.extension.en.topmanhua
|
||||
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import okhttp3.Headers
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
||||
class TopManhua : Madara("Top Manhua", "https://topmanhua.com", "en", SimpleDateFormat("MM/dd/yy", Locale.US)) {
|
||||
override fun headersBuilder(): Headers.Builder = super.headersBuilder().add("Referer", baseUrl)
|
||||
|
||||
// The website does not flag the content.
|
||||
override val filterNonMangaItems = false
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ class YANPFansub : Madara(
|
|||
// Scanlator changed the theme from WpMangaReader to Madara.
|
||||
override val versionId: Int = 2
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(1, 2, TimeUnit.SECONDS)
|
||||
.addInterceptor(::checkPasswordProtectedIntercept)
|
||||
.build()
|
||||
|
|
|
@ -4,7 +4,6 @@ import eu.kanade.tachiyomi.multisrc.madara.Madara
|
|||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import eu.kanade.tachiyomi.source.model.Page
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import org.jsoup.nodes.Document
|
||||
|
@ -19,10 +18,7 @@ class YaoiToshokan : Madara(
|
|||
SimpleDateFormat("dd MMM yyyy", Locale("pt", "BR")),
|
||||
) {
|
||||
|
||||
override fun headersBuilder(): Headers.Builder = super.headersBuilder()
|
||||
.removeAll("User-Agent")
|
||||
|
||||
override val client: OkHttpClient = network.client.newBuilder()
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(1, 2, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
package eu.kanade.tachiyomi.extension.pt.yugenmangas
|
||||
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.lib.randomua.UserAgentType
|
||||
import eu.kanade.tachiyomi.lib.randomua.setRandomUserAgent
|
||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import eu.kanade.tachiyomi.source.model.SChapter
|
||||
import okhttp3.Headers
|
||||
import okhttp3.OkHttpClient
|
||||
import org.jsoup.nodes.Element
|
||||
import java.text.SimpleDateFormat
|
||||
|
@ -17,14 +19,17 @@ class YugenMangas : Madara(
|
|||
SimpleDateFormat("MMMMM dd, yyyy", Locale("pt", "BR")),
|
||||
) {
|
||||
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.addInterceptor(uaIntercept)
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.setRandomUserAgent(
|
||||
UserAgentType.DESKTOP,
|
||||
)
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
.rateLimit(1, 3, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
override fun headersBuilder(): Headers.Builder = Headers.Builder()
|
||||
override fun headersBuilder() = super.headersBuilder()
|
||||
.add("Origin", baseUrl)
|
||||
.add("Referer", "$baseUrl/")
|
||||
|
||||
override val useNewChapterEndpoint: Boolean = true
|
||||
|
||||
|
@ -41,5 +46,5 @@ class YugenMangas : Madara(
|
|||
)
|
||||
}
|
||||
|
||||
override val useRandomUserAgentByDefault: Boolean = true
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) { }
|
||||
}
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
dependencies {
|
||||
implementation(project(":lib-randomua"))
|
||||
}
|
|
@ -35,11 +35,8 @@ class AsuraScansEn : MangaThemesia(
|
|||
|
||||
private val preferences = Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.addInterceptor(::urlChangeInterceptor)
|
||||
.addInterceptor(uaIntercept)
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
.rateLimit(1, 3, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
|
@ -232,7 +229,7 @@ class AsuraScansEn : MangaThemesia(
|
|||
setDefaultValue(true)
|
||||
}.also(screen::addPreference)
|
||||
|
||||
addRandomAndCustomUserAgentPreferences(screen)
|
||||
super.setupPreferenceScreen(screen)
|
||||
}
|
||||
|
||||
private val SharedPreferences.permaUrlPref
|
||||
|
|
|
@ -19,10 +19,7 @@ class AsuraScansTr : MangaThemesia(
|
|||
"tr",
|
||||
dateFormat = SimpleDateFormat("MMM d, yyyy", Locale("tr")),
|
||||
) {
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.addInterceptor(uaIntercept)
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(1, 3, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -3,13 +3,10 @@ package eu.kanade.tachiyomi.extension.id.boosei
|
|||
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import okhttp3.OkHttpClient
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class Boosei : MangaThemesia("Boosei", "https://boosei.net", "id") {
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(4)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import android.webkit.ConsoleMessage
|
|||
import android.webkit.JavascriptInterface
|
||||
import android.webkit.WebChromeClient
|
||||
import android.webkit.WebView
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.lib.dataimage.DataImageInterceptor
|
||||
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
|
@ -149,6 +150,8 @@ class ConstellarScans : MangaThemesia("Constellar Scans", "https://constellarsca
|
|||
.header("Sec-Fetch-Site", "same-origin")
|
||||
.build()
|
||||
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) { }
|
||||
|
||||
companion object {
|
||||
const val UA_DB_URL =
|
||||
"https://cdn.jsdelivr.net/gh/mimmi20/browscap-helper@30a83c095688f40b9eaca0165a479c661e5a7fbe/tests/0002999.json"
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
dependencies {
|
||||
implementation(project(":lib-randomua"))
|
||||
}
|
|
@ -3,13 +3,10 @@ package eu.kanade.tachiyomi.extension.id.dojingnet
|
|||
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import okhttp3.OkHttpClient
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class DojingNet : MangaThemesia("Dojing.net", "https://dojing.net", "id") {
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(4)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -28,7 +28,6 @@ import uy.kohesive.injekt.api.get
|
|||
import java.io.ByteArrayOutputStream
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
open class FlameScans(
|
||||
override val baseUrl: String,
|
||||
|
@ -48,9 +47,7 @@ open class FlameScans(
|
|||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||
}
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.addInterceptor(::composedImageIntercept)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ class FranxxMangas : MangaThemesia(
|
|||
dateFormat = SimpleDateFormat("MMMMM dd, yyyy", Locale("pt", "BR")),
|
||||
) {
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(1, 2, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -6,15 +6,12 @@ import okhttp3.OkHttpClient
|
|||
import org.jsoup.nodes.Document
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class Kiryuu : MangaThemesia("Kiryuu", "https://kiryuu.id", "id", dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale("id"))) {
|
||||
// Formerly "Kiryuu (WP Manga Stream)"
|
||||
override val id = 3639673976007021338
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(4)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ import okhttp3.OkHttpClient
|
|||
import okhttp3.Request
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class KomikAV : MangaThemesia(
|
||||
"Komik AV (WP Manga Stream)",
|
||||
|
@ -19,9 +18,7 @@ class KomikAV : MangaThemesia(
|
|||
// Formerly "Komik AV (WP Manga Stream)"
|
||||
override val id = 7875815514004535629
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(4)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -17,7 +17,6 @@ import org.jsoup.Jsoup
|
|||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import java.util.Calendar
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class KomikCast : MangaThemesia(
|
||||
"Komik Cast",
|
||||
|
@ -28,13 +27,11 @@ class KomikCast : MangaThemesia(
|
|||
// Formerly "Komik Cast (WP Manga Stream)"
|
||||
override val id = 972717448578983812
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(3)
|
||||
.build()
|
||||
|
||||
override fun headersBuilder(): Headers.Builder = Headers.Builder()
|
||||
override fun headersBuilder(): Headers.Builder = super.headersBuilder()
|
||||
.add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9")
|
||||
.add("Accept-language", "en-US,en;q=0.9,id;q=0.8")
|
||||
.add("Referer", baseUrl)
|
||||
|
@ -76,7 +73,7 @@ class KomikCast : MangaThemesia(
|
|||
override fun chapterFromElement(element: Element) = SChapter.create().apply {
|
||||
val urlElements = element.select("a")
|
||||
setUrlWithoutDomain(urlElements.attr("href"))
|
||||
name = element.select(".lch a, .chapternum")!!.text().ifBlank { urlElements.first()!!.text() }
|
||||
name = element.select(".lch a, .chapternum").text().ifBlank { urlElements.first()!!.text() }
|
||||
date_upload = parseChapterDate2(element.select(".chapter-link-time").text())
|
||||
}
|
||||
|
||||
|
|
|
@ -3,12 +3,9 @@ package eu.kanade.tachiyomi.extension.id.komikdewasa
|
|||
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import okhttp3.OkHttpClient
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class KomikDewasa : MangaThemesia("KomikDewasa", "https://komikdewasa.org", "id", "/komik") {
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(4)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -5,15 +5,12 @@ import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
|||
import okhttp3.OkHttpClient
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class KomikindoCo : MangaThemesia("KomikIndo.co", "https://komikindo.co", "id", dateFormat = SimpleDateFormat("MMM dd, yyyy", Locale("id"))) {
|
||||
// Formerly "Komikindo.co"
|
||||
override val id = 734619124437406170
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(4)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -3,12 +3,9 @@ package eu.kanade.tachiyomi.extension.id.komikmanhwa
|
|||
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import okhttp3.OkHttpClient
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class KomikManhwa : MangaThemesia("KomikManhwa", "https://komikmanhwa.me", "id", "/series") {
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(4)
|
||||
.build()
|
||||
}
|
||||
|
|
|
@ -3,15 +3,12 @@ package eu.kanade.tachiyomi.extension.id.komikstation
|
|||
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import okhttp3.OkHttpClient
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class KomikStation : MangaThemesia("Komik Station", "https://komikstation.co", "id") {
|
||||
// Formerly "Komik Station (WP Manga Stream)"
|
||||
override val id = 6148605743576635261
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(4)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -3,12 +3,9 @@ package eu.kanade.tachiyomi.extension.id.kumapoi
|
|||
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import okhttp3.OkHttpClient
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class KumaPoi : MangaThemesia("KumaPoi", "https://kumapoi.club", "id") {
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(4)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -3,13 +3,10 @@ package eu.kanade.tachiyomi.extension.en.kumascans
|
|||
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import okhttp3.OkHttpClient
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class KumaScans : MangaThemesia("Kuma Scans (Kuma Translation)", "https://kumascans.com", "en") {
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(4)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -3,13 +3,10 @@ package eu.kanade.tachiyomi.extension.id.lianscans
|
|||
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import okhttp3.OkHttpClient
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class LianScans : MangaThemesia("LianScans", "https://www.lianscans.my.id", "id") {
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(4)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -3,13 +3,10 @@ package eu.kanade.tachiyomi.extension.id.mangakyo
|
|||
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import okhttp3.OkHttpClient
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class Mangakyo : MangaThemesia("Mangakyo", "https://mangakyo.id", "id") {
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(4)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -15,14 +15,11 @@ import okhttp3.Response
|
|||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import rx.Observable
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class MangaRawOrg : MangaThemesia("Manga Raw.org", "https://mangaraw.org", "ja") {
|
||||
override val id = 6223520752496636410
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(4)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ class MangasChan : MangaThemesia(
|
|||
dateFormat = SimpleDateFormat("MMMMM dd, yyyy", Locale("pt", "BR")),
|
||||
) {
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(1, 2, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -3,13 +3,10 @@ package eu.kanade.tachiyomi.extension.id.mangayaro
|
|||
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import okhttp3.OkHttpClient
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class Mangayaro : MangaThemesia("Mangayaro", "https://mangayaro.net", "id") {
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(4)
|
||||
.build()
|
||||
}
|
||||
|
|
|
@ -3,15 +3,12 @@ package eu.kanade.tachiyomi.extension.id.mangceh
|
|||
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import okhttp3.OkHttpClient
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class Mareceh : MangaThemesia("Mareceh", "https://mareceh.com", "id") {
|
||||
|
||||
override val versionId = 2
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(4)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ class MangKomik : MangaThemesia("MangKomik", "https://mangkomik.net", "id") {
|
|||
|
||||
override fun pageListParse(document: Document): List<Page> {
|
||||
// Get external JS for image urls
|
||||
val scriptEl = document.selectFirst("script[data-minify]")!!
|
||||
val scriptEl = document.selectFirst("script[data-minify]")
|
||||
val scriptUrl = scriptEl?.attr("src")
|
||||
if (scriptUrl.isNullOrEmpty()) {
|
||||
return super.pageListParse(document)
|
||||
|
|
|
@ -3,13 +3,10 @@ package eu.kanade.tachiyomi.extension.id.manhwadesu
|
|||
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import okhttp3.OkHttpClient
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class ManhwaDesu : MangaThemesia("ManhwaDesu", "https://manhwadesu.org", "id", "/komik") {
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(4)
|
||||
.build()
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ class ManhwaFreak : MangaThemesia("Manhwa Freak", "https://manhwafreak.com", "en
|
|||
override fun chapterFromElement(element: Element) = SChapter.create().apply {
|
||||
val urlElements = element.select("a")
|
||||
setUrlWithoutDomain(urlElements.attr("href"))
|
||||
name = element.select(".chapter-info p:nth-child(1)")!!.text().ifBlank { urlElements.first()!!.text() }
|
||||
name = element.select(".chapter-info p:nth-child(1)").text().ifBlank { urlElements.first()!!.text() }
|
||||
date_upload = element.selectFirst(".chapter-info p:nth-child(2)")?.text().parseChapterDate()
|
||||
}
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ class ManhwaIndo : MangaThemesia(
|
|||
SimpleDateFormat("MMMM dd, yyyy", Locale("id")),
|
||||
) {
|
||||
|
||||
override fun headersBuilder(): Headers.Builder = Headers.Builder()
|
||||
override fun headersBuilder(): Headers.Builder = super.headersBuilder()
|
||||
.add("Referer", baseUrl)
|
||||
|
||||
override fun mangaDetailsParse(document: Document) = super.mangaDetailsParse(document).apply {
|
||||
|
|
|
@ -3,13 +3,10 @@ package eu.kanade.tachiyomi.extension.id.manhwalandmom
|
|||
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import okhttp3.OkHttpClient
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class ManhwaLandMom : MangaThemesia("ManhwaLand.mom", "https://manhwaland.us", "id") {
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(4)
|
||||
.build()
|
||||
}
|
||||
|
|
|
@ -3,13 +3,10 @@ package eu.kanade.tachiyomi.extension.id.manhwalist
|
|||
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import okhttp3.OkHttpClient
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class ManhwaList : MangaThemesia("ManhwaList", "https://manhwalist.xyz", "id") {
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(4)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -3,13 +3,10 @@ package eu.kanade.tachiyomi.extension.id.masterkomik
|
|||
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import okhttp3.OkHttpClient
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class MasterKomik : MangaThemesia("MasterKomik", "https://masterkomik.com", "id") {
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(4)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -3,12 +3,9 @@ package eu.kanade.tachiyomi.extension.id.mirrordesu
|
|||
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import okhttp3.OkHttpClient
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class MirrorDesu : MangaThemesia("MirrorDesu", "https://mirrordesu.me", "id", "/komik") {
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(4)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ class ModeScanlator : MangaThemesia(
|
|||
// Site changed from Madara to WpMangaReader.
|
||||
override val versionId: Int = 2
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(1, 2, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -3,13 +3,10 @@ package eu.kanade.tachiyomi.extension.id.nekomik
|
|||
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import okhttp3.OkHttpClient
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class Nekomik : MangaThemesia("Nekomik", "https://nekomik.com", "id") {
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(4)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@ class OrigamiOrpheans : MangaThemesia(
|
|||
// Scanlator migrated from Madara to WpMangaReader.
|
||||
override val versionId = 2
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(1, 2, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -3,13 +3,10 @@ package eu.kanade.tachiyomi.extension.ja.rawkuma
|
|||
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import okhttp3.OkHttpClient
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class Rawkuma : MangaThemesia("Rawkuma", "https://rawkuma.com/", "ja") {
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(4)
|
||||
.build()
|
||||
}
|
||||
|
|
|
@ -3,13 +3,10 @@ package eu.kanade.tachiyomi.extension.en.readkomik
|
|||
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import okhttp3.OkHttpClient
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class ReadKomik : MangaThemesia("Readkomik", "https://readkomik.com", "en") {
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(4)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -3,13 +3,10 @@ package eu.kanade.tachiyomi.extension.id.ryukonesia
|
|||
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import okhttp3.OkHttpClient
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class Ryukonesia : MangaThemesia("Ryukonesia", "https://ryukonesia.net", "id") {
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(4)
|
||||
.build()
|
||||
}
|
||||
|
|
|
@ -5,13 +5,10 @@ import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
|||
import okhttp3.OkHttpClient
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class SekteDoujin : MangaThemesia("Sekte Doujin", "https://sektedoujin.lol", "id", dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale.forLanguageTag("id"))) {
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(4)
|
||||
.build()
|
||||
}
|
||||
|
|
|
@ -6,7 +6,6 @@ import okhttp3.Dns
|
|||
import okhttp3.OkHttpClient
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class SheaManga : MangaThemesia(
|
||||
"Shea Manga",
|
||||
|
@ -15,9 +14,7 @@ class SheaManga : MangaThemesia(
|
|||
dateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale.forLanguageTag("id")),
|
||||
) {
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(4)
|
||||
.dns(Dns.SYSTEM)
|
||||
.build()
|
||||
|
|
|
@ -17,9 +17,7 @@ class SilenceScan : MangaThemesia(
|
|||
|
||||
override val versionId: Int = 2
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(1, 2, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ class TsundokuTraducoes : MangaThemesia(
|
|||
dateFormat = SimpleDateFormat("MMMMM d, yyyy", Locale("pt", "BR")),
|
||||
) {
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(1, 2, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -3,15 +3,12 @@ package eu.kanade.tachiyomi.extension.id.westmanga
|
|||
import eu.kanade.tachiyomi.multisrc.mangathemesia.MangaThemesia
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
import okhttp3.OkHttpClient
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class WestManga : MangaThemesia("West Manga", "https://westmanga.info", "id") {
|
||||
// Formerly "West Manga (WP Manga Stream)"
|
||||
override val id = 8883916630998758688
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.rateLimit(4)
|
||||
.build()
|
||||
|
||||
|
|
|
@ -8,13 +8,10 @@ import okhttp3.HttpUrl.Companion.toHttpUrl
|
|||
import okhttp3.OkHttpClient
|
||||
import org.jsoup.nodes.Document
|
||||
import org.jsoup.nodes.Element
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
||||
class xCaliBRScans : MangaThemesia("xCaliBR Scans", "https://xcalibrscans.com", "en") {
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.addInterceptor(AntiScrapInterceptor())
|
||||
.rateLimit(2)
|
||||
.build()
|
||||
|
|
|
@ -3,12 +3,10 @@ package eu.kanade.tachiyomi.multisrc.madara
|
|||
import android.app.Application
|
||||
import android.content.SharedPreferences
|
||||
import android.util.Base64
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.preference.EditTextPreference
|
||||
import androidx.preference.PreferenceScreen
|
||||
import androidx.preference.SwitchPreferenceCompat
|
||||
import eu.kanade.tachiyomi.lib.cryptoaes.CryptoAES
|
||||
import eu.kanade.tachiyomi.lib.randomua.RandomUserAgentPreference
|
||||
import eu.kanade.tachiyomi.lib.randomua.setRandomUserAgent
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.network.asObservable
|
||||
|
@ -21,17 +19,13 @@ import eu.kanade.tachiyomi.source.model.SChapter
|
|||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.jsonObject
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
import okhttp3.CacheControl
|
||||
import okhttp3.FormBody
|
||||
import okhttp3.Headers
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
|
@ -40,7 +34,6 @@ import rx.Observable
|
|||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.IOException
|
||||
import java.text.ParseException
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Calendar
|
||||
|
@ -58,91 +51,24 @@ abstract class Madara(
|
|||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||
}
|
||||
|
||||
private val randomUAPrefHelper: RandomUserAgentPreference by lazy {
|
||||
RandomUserAgentPreference(preferences)
|
||||
}
|
||||
|
||||
override val supportsLatest = true
|
||||
|
||||
// override with true if you want useRandomUserAgentByDefault to be on by default for some source
|
||||
protected open val useRandomUserAgentByDefault: Boolean = false
|
||||
|
||||
/**
|
||||
* override include/exclude user-agent string if needed
|
||||
* some example:
|
||||
* listOf("chrome")
|
||||
* listOf("linux", "windows")
|
||||
* listOf("108")
|
||||
*/
|
||||
protected open val filterIncludeUserAgent: List<String> = listOf()
|
||||
protected open val filterExcludeUserAgent: List<String> = listOf()
|
||||
|
||||
private var userAgent: String? = null
|
||||
private var checkedUa = false
|
||||
|
||||
private val hasUaIntercept by lazy {
|
||||
client.interceptors.toString().contains("uaIntercept")
|
||||
}
|
||||
|
||||
protected val uaIntercept = object : Interceptor {
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val useRandomUa = preferences.getBoolean(PREF_KEY_RANDOM_UA, false)
|
||||
val customUa = preferences.getString(PREF_KEY_CUSTOM_UA, "")
|
||||
|
||||
try {
|
||||
if (hasUaIntercept && (useRandomUa || customUa!!.isNotBlank())) {
|
||||
Log.i("Extension_setting", "$TITLE_RANDOM_UA or $TITLE_CUSTOM_UA option is ENABLED")
|
||||
|
||||
if (customUa!!.isNotBlank() && useRandomUa.not()) {
|
||||
userAgent = customUa
|
||||
}
|
||||
|
||||
if (userAgent.isNullOrBlank() && !checkedUa) {
|
||||
val uaResponse = chain.proceed(GET(UA_DB_URL))
|
||||
|
||||
if (uaResponse.isSuccessful) {
|
||||
var listUserAgentString =
|
||||
json.decodeFromString<Map<String, List<String>>>(uaResponse.body.string())["desktop"]
|
||||
|
||||
if (filterIncludeUserAgent.isNotEmpty()) {
|
||||
listUserAgentString = listUserAgentString!!.filter {
|
||||
filterIncludeUserAgent.any { filter ->
|
||||
it.contains(filter, ignoreCase = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (filterExcludeUserAgent.isNotEmpty()) {
|
||||
listUserAgentString = listUserAgentString!!.filterNot {
|
||||
filterExcludeUserAgent.any { filter ->
|
||||
it.contains(filter, ignoreCase = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
userAgent = listUserAgentString!!.random()
|
||||
checkedUa = true
|
||||
}
|
||||
|
||||
uaResponse.close()
|
||||
}
|
||||
|
||||
if (userAgent.isNullOrBlank().not()) {
|
||||
val newRequest = chain.request().newBuilder()
|
||||
.header("User-Agent", userAgent!!.trim())
|
||||
.build()
|
||||
|
||||
return chain.proceed(newRequest)
|
||||
}
|
||||
}
|
||||
|
||||
return chain.proceed(chain.request())
|
||||
} catch (e: Exception) {
|
||||
throw IOException(e.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.addInterceptor(uaIntercept)
|
||||
override val client = network.cloudflareClient.newBuilder()
|
||||
.setRandomUserAgent(
|
||||
randomUAPrefHelper.getPrefUAType(),
|
||||
randomUAPrefHelper.getPrefCustomUA(),
|
||||
)
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
||||
override fun headersBuilder() = super.headersBuilder()
|
||||
.add("Referer", "$baseUrl/")
|
||||
|
||||
protected open val json: Json by injectLazy()
|
||||
|
||||
/**
|
||||
|
@ -187,9 +113,6 @@ abstract class Madara(
|
|||
*/
|
||||
protected open val mangaSubString = "manga"
|
||||
|
||||
override fun headersBuilder(): Headers.Builder = Headers.Builder()
|
||||
.add("Referer", "$baseUrl/")
|
||||
|
||||
// Popular Manga
|
||||
|
||||
override fun popularMangaParse(response: Response): MangasPage {
|
||||
|
@ -1017,57 +940,6 @@ abstract class Madara(
|
|||
}
|
||||
}
|
||||
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||
if (hasUaIntercept) {
|
||||
val prefUserAgent = SwitchPreferenceCompat(screen.context).apply {
|
||||
key = PREF_KEY_RANDOM_UA
|
||||
title = TITLE_RANDOM_UA
|
||||
summary = if (preferences.getBoolean(PREF_KEY_RANDOM_UA, useRandomUserAgentByDefault)) userAgent else ""
|
||||
setDefaultValue(useRandomUserAgentByDefault)
|
||||
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
val useRandomUa = newValue as Boolean
|
||||
preferences.edit().putBoolean(PREF_KEY_RANDOM_UA, useRandomUa).apply()
|
||||
if (!useRandomUa) {
|
||||
Toast.makeText(screen.context, RESTART_APP_STRING, Toast.LENGTH_LONG).show()
|
||||
} else {
|
||||
userAgent = null
|
||||
if (preferences.getString(PREF_KEY_CUSTOM_UA, "").isNullOrBlank().not()) {
|
||||
Toast.makeText(screen.context, SUMMARY_CLEANING_CUSTOM_UA, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
preferences.edit().putString(PREF_KEY_CUSTOM_UA, "").apply()
|
||||
// prefCustomUserAgent.summary = ""
|
||||
true
|
||||
}
|
||||
}
|
||||
screen.addPreference(prefUserAgent)
|
||||
|
||||
val prefCustomUserAgent = EditTextPreference(screen.context).apply {
|
||||
key = PREF_KEY_CUSTOM_UA
|
||||
title = TITLE_CUSTOM_UA
|
||||
summary = preferences.getString(PREF_KEY_CUSTOM_UA, "")!!.trim()
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
val customUa = newValue as String
|
||||
preferences.edit().putString(PREF_KEY_CUSTOM_UA, customUa).apply()
|
||||
if (customUa.isBlank()) {
|
||||
Toast.makeText(screen.context, RESTART_APP_STRING, Toast.LENGTH_LONG).show()
|
||||
} else {
|
||||
userAgent = null
|
||||
}
|
||||
summary = customUa.trim()
|
||||
prefUserAgent.summary = ""
|
||||
prefUserAgent.isChecked = false
|
||||
true
|
||||
}
|
||||
}
|
||||
screen.addPreference(prefCustomUserAgent)
|
||||
} else {
|
||||
Toast.makeText(screen.context, DOESNOT_SUPPORT_STRING, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/66614516
|
||||
private fun String.decodeHex(): ByteArray {
|
||||
check(length % 2 == 0) { "Must have an even length" }
|
||||
|
@ -1077,20 +949,12 @@ abstract class Madara(
|
|||
.toByteArray()
|
||||
}
|
||||
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||
randomUAPrefHelper.addPreferenceToScreen(screen)
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val TITLE_RANDOM_UA = "Use Random Latest User-Agent"
|
||||
const val PREF_KEY_RANDOM_UA = "pref_key_random_ua"
|
||||
|
||||
const val TITLE_CUSTOM_UA = "Custom User-Agent"
|
||||
const val PREF_KEY_CUSTOM_UA = "pref_key_custom_ua"
|
||||
|
||||
const val SUMMARY_CLEANING_CUSTOM_UA = "$TITLE_CUSTOM_UA cleared."
|
||||
|
||||
const val RESTART_APP_STRING = "Restart Tachiyomi to apply new setting."
|
||||
const val DOESNOT_SUPPORT_STRING = "This extension doesn't support User-Agent options."
|
||||
const val URL_SEARCH_PREFIX = "slug:"
|
||||
private const val UA_DB_URL = "https://tachiyomiorg.github.io/user-agents/user-agents.json"
|
||||
|
||||
val SALTED = "Salted__".toByteArray(Charsets.UTF_8)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ class MadaraGenerator : ThemeSourceGenerator {
|
|||
|
||||
override val themeClass = "Madara"
|
||||
|
||||
override val baseVersionCode: Int = 30
|
||||
override val baseVersionCode: Int = 31
|
||||
|
||||
override val sources = listOf(
|
||||
MultiLang("Atlantis Scan", "https://atlantisscan.com", listOf("es", "pt-BR"), isNsfw = true),
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
package eu.kanade.tachiyomi.multisrc.mangahub
|
||||
|
||||
import eu.kanade.tachiyomi.lib.randomua.UserAgentType
|
||||
import eu.kanade.tachiyomi.lib.randomua.setRandomUserAgent
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
|
@ -48,7 +50,10 @@ abstract class MangaHub(
|
|||
private var baseCdnUrl = "https://imgx.mghubcdn.com"
|
||||
|
||||
override val client: OkHttpClient = super.client.newBuilder()
|
||||
.addInterceptor(::uaIntercept)
|
||||
.setRandomUserAgent(
|
||||
userAgentType = UserAgentType.DESKTOP,
|
||||
filterInclude = listOf("chrome"),
|
||||
)
|
||||
.addInterceptor(::apiAuthInterceptor)
|
||||
.rateLimit(1)
|
||||
.build()
|
||||
|
@ -65,35 +70,6 @@ abstract class MangaHub(
|
|||
|
||||
open val json: Json by injectLazy()
|
||||
|
||||
private var userAgent: String? = null
|
||||
private var checkedUa = false
|
||||
|
||||
private fun uaIntercept(chain: Interceptor.Chain): Response {
|
||||
if (userAgent == null && !checkedUa) {
|
||||
val uaResponse = chain.proceed(GET(UA_DB_URL))
|
||||
|
||||
if (uaResponse.isSuccessful) {
|
||||
// only using desktop chromium-based browsers, apparently they refuse to load(403) if not chrome(ium)
|
||||
val uaList = json.decodeFromString<Map<String, List<String>>>(uaResponse.body.string())
|
||||
val chromeUserAgentString = uaList["desktop"]!!.filter { it.contains("chrome", ignoreCase = true) }
|
||||
userAgent = chromeUserAgentString.random()
|
||||
checkedUa = true
|
||||
}
|
||||
|
||||
uaResponse.close()
|
||||
}
|
||||
|
||||
if (userAgent != null) {
|
||||
val newRequest = chain.request().newBuilder()
|
||||
.header("User-Agent", userAgent!!)
|
||||
.build()
|
||||
|
||||
return chain.proceed(newRequest)
|
||||
}
|
||||
|
||||
return chain.proceed(chain.request())
|
||||
}
|
||||
|
||||
private fun apiAuthInterceptor(chain: Interceptor.Chain): Response {
|
||||
val originalRequest = chain.request()
|
||||
|
||||
|
@ -514,8 +490,4 @@ abstract class MangaHub(
|
|||
Genre("Wuxia", "wuxia"),
|
||||
Genre("Yuri", "yuri"),
|
||||
)
|
||||
|
||||
companion object {
|
||||
private const val UA_DB_URL = "https://tachiyomiorg.github.io/user-agents/user-agents.json"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ class MangaHubGenerator : ThemeSourceGenerator {
|
|||
|
||||
override val themeClass = "MangaHub"
|
||||
|
||||
override val baseVersionCode: Int = 21
|
||||
override val baseVersionCode: Int = 22
|
||||
|
||||
override val sources = listOf(
|
||||
// SingleLang("1Manga.co", "https://1manga.co", "en", isNsfw = true, className = "OneMangaCo"),
|
||||
|
|
|
@ -2,11 +2,9 @@ package eu.kanade.tachiyomi.multisrc.mangathemesia
|
|||
|
||||
import android.app.Application
|
||||
import android.content.SharedPreferences
|
||||
import android.util.Log
|
||||
import android.widget.Toast
|
||||
import androidx.preference.EditTextPreference
|
||||
import androidx.preference.PreferenceScreen
|
||||
import androidx.preference.SwitchPreferenceCompat
|
||||
import eu.kanade.tachiyomi.lib.randomua.RandomUserAgentPreference
|
||||
import eu.kanade.tachiyomi.lib.randomua.setRandomUserAgent
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.POST
|
||||
import eu.kanade.tachiyomi.source.ConfigurableSource
|
||||
|
@ -18,7 +16,6 @@ import eu.kanade.tachiyomi.source.model.SChapter
|
|||
import eu.kanade.tachiyomi.source.model.SManga
|
||||
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.Json
|
||||
import kotlinx.serialization.json.jsonArray
|
||||
import kotlinx.serialization.json.jsonPrimitive
|
||||
|
@ -26,8 +23,6 @@ import okhttp3.FormBody
|
|||
import okhttp3.HttpUrl
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import okhttp3.Interceptor
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
|
@ -37,7 +32,6 @@ import rx.Observable
|
|||
import uy.kohesive.injekt.Injekt
|
||||
import uy.kohesive.injekt.api.get
|
||||
import uy.kohesive.injekt.injectLazy
|
||||
import java.io.IOException
|
||||
import java.lang.IllegalArgumentException
|
||||
import java.text.SimpleDateFormat
|
||||
import java.util.Locale
|
||||
|
@ -56,82 +50,19 @@ abstract class MangaThemesia(
|
|||
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
|
||||
}
|
||||
|
||||
private val randomUAPrefHelper: RandomUserAgentPreference by lazy {
|
||||
RandomUserAgentPreference(preferences)
|
||||
}
|
||||
|
||||
protected open val json: Json by injectLazy()
|
||||
|
||||
override val supportsLatest = true
|
||||
|
||||
// override with true if you want useRandomUserAgentByDefault to be on by default for some source
|
||||
protected open val useRandomUserAgentByDefault: Boolean = false
|
||||
|
||||
protected open val filterIncludeUserAgent: List<String> = listOf()
|
||||
protected open val filterExcludeUserAgent: List<String> = listOf()
|
||||
|
||||
private var userAgent: String? = null
|
||||
private var checkedUa = false
|
||||
|
||||
protected val hasUaIntercept by lazy {
|
||||
client.interceptors.toString().contains("uaIntercept")
|
||||
}
|
||||
|
||||
protected val uaIntercept = object : Interceptor {
|
||||
override fun intercept(chain: Interceptor.Chain): Response {
|
||||
val useRandomUa = preferences.getBoolean(PREF_KEY_RANDOM_UA, false)
|
||||
val customUa = preferences.getString(PREF_KEY_CUSTOM_UA, "")
|
||||
|
||||
try {
|
||||
if (hasUaIntercept && (useRandomUa || customUa!!.isNotBlank())) {
|
||||
Log.i("Extension_setting", "$TITLE_RANDOM_UA or $TITLE_CUSTOM_UA option is ENABLED")
|
||||
|
||||
if (customUa!!.isNotBlank() && useRandomUa.not()) {
|
||||
userAgent = customUa
|
||||
}
|
||||
|
||||
if (userAgent.isNullOrBlank() && !checkedUa) {
|
||||
val uaResponse = chain.proceed(GET(UA_DB_URL))
|
||||
|
||||
if (uaResponse.isSuccessful) {
|
||||
var listUserAgentString =
|
||||
json.decodeFromString<Map<String, List<String>>>(uaResponse.body.string())["desktop"]
|
||||
|
||||
if (filterIncludeUserAgent.isNotEmpty()) {
|
||||
listUserAgentString = listUserAgentString!!.filter {
|
||||
filterIncludeUserAgent.any { filter ->
|
||||
it.contains(filter, ignoreCase = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
if (filterExcludeUserAgent.isNotEmpty()) {
|
||||
listUserAgentString = listUserAgentString!!.filterNot {
|
||||
filterExcludeUserAgent.any { filter ->
|
||||
it.contains(filter, ignoreCase = true)
|
||||
}
|
||||
}
|
||||
}
|
||||
userAgent = listUserAgentString!!.random()
|
||||
checkedUa = true
|
||||
}
|
||||
|
||||
uaResponse.close()
|
||||
}
|
||||
|
||||
if (userAgent.isNullOrBlank().not()) {
|
||||
val newRequest = chain.request().newBuilder()
|
||||
.header("User-Agent", userAgent!!.trim())
|
||||
.build()
|
||||
|
||||
return chain.proceed(newRequest)
|
||||
}
|
||||
}
|
||||
|
||||
return chain.proceed(chain.request())
|
||||
} catch (e: Exception) {
|
||||
throw IOException(e.message)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
.addInterceptor(uaIntercept)
|
||||
override val client = network.cloudflareClient.newBuilder()
|
||||
.setRandomUserAgent(
|
||||
randomUAPrefHelper.getPrefUAType(),
|
||||
randomUAPrefHelper.getPrefCustomUA(),
|
||||
)
|
||||
.connectTimeout(10, TimeUnit.SECONDS)
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
.build()
|
||||
|
@ -524,7 +455,9 @@ abstract class MangaThemesia(
|
|||
val links = response.asJsoup().select("a[itemprop=item]")
|
||||
// near the top of page: home > manga > current chapter
|
||||
if (links.size == 3) {
|
||||
return links[1].attr("href").toHttpUrlOrNull()?.encodedPath
|
||||
val newUrl = links[1].attr("href").toHttpUrlOrNull() ?: return null
|
||||
val isNewMangaUrl = (baseMangaUrl.host == newUrl.host && pathLengthIs(newUrl, 2) && newUrl.pathSegments[0] == baseMangaUrl.pathSegments[0])
|
||||
if (isNewMangaUrl) return newUrl.pathSegments[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -566,58 +499,7 @@ abstract class MangaThemesia(
|
|||
override fun imageUrlParse(document: Document): String = throw UnsupportedOperationException("Not Used")
|
||||
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||
addRandomAndCustomUserAgentPreferences(screen)
|
||||
}
|
||||
|
||||
protected fun addRandomAndCustomUserAgentPreferences(screen: PreferenceScreen) {
|
||||
if (!hasUaIntercept) {
|
||||
return // Unable to change the user agent. Therefore the preferences won't be displayed.
|
||||
}
|
||||
|
||||
val prefRandomUserAgent = SwitchPreferenceCompat(screen.context).apply {
|
||||
key = PREF_KEY_RANDOM_UA
|
||||
title = TITLE_RANDOM_UA
|
||||
summary = if (preferences.getBoolean(PREF_KEY_RANDOM_UA, useRandomUserAgentByDefault)) userAgent else ""
|
||||
setDefaultValue(useRandomUserAgentByDefault)
|
||||
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
val useRandomUa = newValue as Boolean
|
||||
preferences.edit().putBoolean(PREF_KEY_RANDOM_UA, useRandomUa).apply()
|
||||
if (!useRandomUa) {
|
||||
Toast.makeText(screen.context, RESTART_APP_STRING, Toast.LENGTH_LONG).show()
|
||||
} else {
|
||||
userAgent = null
|
||||
if (preferences.getString(PREF_KEY_CUSTOM_UA, "").isNullOrBlank().not()) {
|
||||
Toast.makeText(screen.context, SUMMARY_CLEANING_CUSTOM_UA, Toast.LENGTH_LONG).show()
|
||||
}
|
||||
}
|
||||
|
||||
preferences.edit().putString(PREF_KEY_CUSTOM_UA, "").apply()
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
val prefCustomUserAgent = EditTextPreference(screen.context).apply {
|
||||
key = PREF_KEY_CUSTOM_UA
|
||||
title = TITLE_CUSTOM_UA
|
||||
summary = preferences.getString(PREF_KEY_CUSTOM_UA, "")!!.trim()
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
val customUa = newValue as String
|
||||
preferences.edit().putString(PREF_KEY_CUSTOM_UA, customUa).apply()
|
||||
if (customUa.isBlank()) {
|
||||
Toast.makeText(screen.context, RESTART_APP_STRING, Toast.LENGTH_LONG).show()
|
||||
} else {
|
||||
userAgent = null
|
||||
}
|
||||
summary = customUa.trim()
|
||||
prefRandomUserAgent.summary = ""
|
||||
prefRandomUserAgent.isChecked = false
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
screen.addPreference(prefRandomUserAgent)
|
||||
screen.addPreference(prefCustomUserAgent)
|
||||
randomUAPrefHelper.addPreferenceToScreen(screen)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
@ -629,16 +511,5 @@ abstract class MangaThemesia(
|
|||
private val CHAPTER_PAGE_ID_REGEX = "chapter_id\\s*=\\s*(\\d+);".toRegex()
|
||||
|
||||
val JSON_IMAGE_LIST_REGEX = "\"images\"\\s*:\\s*(\\[.*?])".toRegex()
|
||||
|
||||
const val TITLE_RANDOM_UA = "Use Random Latest User-Agent"
|
||||
const val PREF_KEY_RANDOM_UA = "pref_key_random_ua"
|
||||
|
||||
const val TITLE_CUSTOM_UA = "Custom User-Agent"
|
||||
const val PREF_KEY_CUSTOM_UA = "pref_key_custom_ua"
|
||||
|
||||
const val SUMMARY_CLEANING_CUSTOM_UA = "$TITLE_CUSTOM_UA cleared."
|
||||
|
||||
const val RESTART_APP_STRING = "Restart Tachiyomi to apply new setting."
|
||||
private const val UA_DB_URL = "https://tachiyomiorg.github.io/user-agents/user-agents.json"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,7 +11,7 @@ class MangaThemesiaGenerator : ThemeSourceGenerator {
|
|||
|
||||
override val themeClass = "MangaThemesia"
|
||||
|
||||
override val baseVersionCode: Int = 25
|
||||
override val baseVersionCode: Int = 26
|
||||
|
||||
override val sources = listOf(
|
||||
MultiLang("Asura Scans", "https://www.asurascans.com", listOf("en", "tr"), className = "AsuraScansFactory", pkgName = "asurascans", overrideVersionCode = 23),
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
include(":core")
|
||||
|
||||
listOf("dataimage", "unpacker", "cryptoaes", "textinterceptor", "synchrony").forEach {
|
||||
include(":lib-$it")
|
||||
project(":lib-$it").projectDir = File("lib/$it")
|
||||
// all the directories under /lib instead of manually adding each to a list
|
||||
File(rootDir, "lib").eachDir {
|
||||
val libName = it.name
|
||||
include(":lib-$libName")
|
||||
project(":lib-$libName").projectDir = File("lib/$libName")
|
||||
}
|
||||
|
||||
if (System.getenv("CI") == null || System.getenv("CI_MODULE_GEN") == "true") {
|
||||
|
|
|
@ -5,8 +5,12 @@ ext {
|
|||
extName = 'NHentai'
|
||||
pkgNameSuffix = 'all.nhentai'
|
||||
extClass = '.NHFactory'
|
||||
extVersionCode = 37
|
||||
extVersionCode = 38
|
||||
isNsfw = true
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":lib-randomua"))
|
||||
}
|
||||
|
||||
apply from: "$rootDir/common.gradle"
|
||||
|
|
|
@ -2,12 +2,16 @@ package eu.kanade.tachiyomi.extension.all.nhentai
|
|||
|
||||
import android.app.Application
|
||||
import android.content.SharedPreferences
|
||||
import androidx.preference.ListPreference
|
||||
import androidx.preference.PreferenceScreen
|
||||
import eu.kanade.tachiyomi.extension.all.nhentai.NHUtils.getArtists
|
||||
import eu.kanade.tachiyomi.extension.all.nhentai.NHUtils.getGroups
|
||||
import eu.kanade.tachiyomi.extension.all.nhentai.NHUtils.getNumPages
|
||||
import eu.kanade.tachiyomi.extension.all.nhentai.NHUtils.getTagDescription
|
||||
import eu.kanade.tachiyomi.extension.all.nhentai.NHUtils.getTags
|
||||
import eu.kanade.tachiyomi.extension.all.nhentai.NHUtils.getTime
|
||||
import eu.kanade.tachiyomi.lib.randomua.UserAgentType
|
||||
import eu.kanade.tachiyomi.lib.randomua.setRandomUserAgent
|
||||
import eu.kanade.tachiyomi.network.GET
|
||||
import eu.kanade.tachiyomi.network.asObservableSuccess
|
||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||
|
@ -22,7 +26,6 @@ import eu.kanade.tachiyomi.source.model.UpdateStrategy
|
|||
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
|
||||
import eu.kanade.tachiyomi.util.asJsoup
|
||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Response
|
||||
import org.jsoup.nodes.Document
|
||||
|
@ -44,7 +47,11 @@ open class NHentai(
|
|||
|
||||
override val supportsLatest = true
|
||||
|
||||
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||
override val client = network.cloudflareClient.newBuilder()
|
||||
.setRandomUserAgent(
|
||||
userAgentType = UserAgentType.MOBILE,
|
||||
filterInclude = listOf("chrome"),
|
||||
)
|
||||
.rateLimit(4)
|
||||
.build()
|
||||
|
||||
|
@ -60,13 +67,14 @@ open class NHentai(
|
|||
private val shortenTitleRegex = Regex("""(\[[^]]*]|[({][^)}]*[)}])""")
|
||||
private fun String.shortenTitle() = this.replace(shortenTitleRegex, "").trim()
|
||||
|
||||
override fun setupPreferenceScreen(screen: androidx.preference.PreferenceScreen) {
|
||||
val serverPref = androidx.preference.ListPreference(screen.context).apply {
|
||||
override fun setupPreferenceScreen(screen: PreferenceScreen) {
|
||||
ListPreference(screen.context).apply {
|
||||
key = TITLE_PREF
|
||||
title = TITLE_PREF
|
||||
entries = arrayOf("Full Title", "Short Title")
|
||||
entryValues = arrayOf("full", "short")
|
||||
summary = "%s"
|
||||
setDefaultValue("full")
|
||||
|
||||
setOnPreferenceChangeListener { _, newValue ->
|
||||
displayFullTitle = when (newValue) {
|
||||
|
@ -75,13 +83,7 @@ open class NHentai(
|
|||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
if (!preferences.contains(TITLE_PREF)) {
|
||||
preferences.edit().putString(TITLE_PREF, "full").apply()
|
||||
}
|
||||
|
||||
screen.addPreference(serverPref)
|
||||
}.also(screen::addPreference)
|
||||
}
|
||||
|
||||
override fun latestUpdatesRequest(page: Int) = GET(if (nhLang.isBlank()) "$baseUrl/?page=$page" else "$baseUrl/language/$nhLang/?page=$page", headers)
|
||||
|
|
Loading…
Reference in New Issue