Madara Custom and Random Latest User-Agent (#14688)

* Random Latest User-Agent v0.5

* use better checker for ::uaIntercept

* update wording

* fix lint 1

* rerun

* rerun 2

* Random Latest User-Agent v0.5

* use better checker for ::uaIntercept

* update wording

* fix lint 1

* rerun

* rerun 2

* add custom useragent and use IOException

* Fix some issue, reuse string

* fix lint 1

* fix lint 2

* fix lint 3

* not supported toast, base version

* add log if setting is on
This commit is contained in:
Luqman 2023-01-05 21:50:27 +07:00 committed by GitHub
parent 58a572a25f
commit 70ff14a274
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 161 additions and 50 deletions

View File

@ -5,7 +5,6 @@ import eu.kanade.tachiyomi.network.GET
import okhttp3.Request
class AdonisFansub : Madara("Adonis Fansub", "https://manga.adonisfansub.com", "tr") {
override val userAgentRandomizer = ""
override fun popularMangaRequest(page: Int): Request = GET("$baseUrl/manga/page/$page/?m_orderby=views", headers)
override fun latestUpdatesRequest(page: Int): Request = GET("$baseUrl/manga/page/$page/?m_orderby=latest", headers)
}

View File

@ -1,16 +1,11 @@
package eu.kanade.tachiyomi.extension.pt.yugenmangas
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.SChapter
import kotlinx.serialization.decodeFromString
import okhttp3.Headers
import okhttp3.Interceptor
import okhttp3.OkHttpClient
import okhttp3.Response
import org.jsoup.nodes.Element
import java.io.IOException
import java.text.SimpleDateFormat
import java.util.Locale
import java.util.concurrent.TimeUnit
@ -23,7 +18,7 @@ class YugenMangas : Madara(
) {
override val client: OkHttpClient = super.client.newBuilder()
.addInterceptor(::uaIntercept)
.addInterceptor(uaIntercept)
.rateLimit(1, 3, TimeUnit.SECONDS)
.build()
@ -49,39 +44,5 @@ class YugenMangas : Madara(
)
}
private var userAgent: String? = null
private var checkedUa = false
private fun uaIntercept(chain: Interceptor.Chain): Response {
try {
if (userAgent == null && !checkedUa) {
val uaResponse = chain.proceed(GET(UA_DB_URL))
if (uaResponse.isSuccessful) {
val uaMap =
json.decodeFromString<Map<String, List<String>>>(uaResponse.body!!.string())
userAgent = uaMap["desktop"]?.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())
} catch (e: Exception) {
throw IOException(e.message)
}
}
companion object {
private const val UA_DB_URL = "https://tachiyomiorg.github.io/user-agents/user-agents.json"
}
override val useRandomUserAgentByDefault: Boolean = true
}

View File

@ -1,8 +1,16 @@
package eu.kanade.tachiyomi.multisrc.madara
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.network.GET
import eu.kanade.tachiyomi.network.POST
import eu.kanade.tachiyomi.network.asObservable
import eu.kanade.tachiyomi.source.ConfigurableSource
import eu.kanade.tachiyomi.source.model.Filter
import eu.kanade.tachiyomi.source.model.FilterList
import eu.kanade.tachiyomi.source.model.MangasPage
@ -11,6 +19,7 @@ import eu.kanade.tachiyomi.source.model.SChapter
import eu.kanade.tachiyomi.source.model.SManga
import eu.kanade.tachiyomi.source.online.ParsedHttpSource
import eu.kanade.tachiyomi.util.asJsoup
import kotlinx.serialization.decodeFromString
import kotlinx.serialization.json.Json
import kotlinx.serialization.json.jsonObject
import kotlinx.serialization.json.jsonPrimitive
@ -18,38 +27,119 @@ 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
import org.jsoup.nodes.Element
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
import java.util.Locale
import java.util.concurrent.TimeUnit
import kotlin.math.absoluteValue
import kotlin.random.Random
abstract class Madara(
override val name: String,
override val baseUrl: String,
final override val lang: String,
private val dateFormat: SimpleDateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale.US)
) : ParsedHttpSource() {
) : ParsedHttpSource(), ConfigurableSource {
private val preferences: SharedPreferences by lazy {
Injekt.get<Application>().getSharedPreferences("source_$id", 0x0000)
}
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)
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build()
// helps with cloudflare for some sources, makes it worse for others; override with empty string if the latter is true
protected open val userAgentRandomizer = " ${Random.nextInt().absoluteValue}"
protected open val json: Json by injectLazy()
/**
@ -79,7 +169,6 @@ abstract class Madara(
protected open val fetchGenres: Boolean = true
override fun headersBuilder(): Headers.Builder = Headers.Builder()
.add("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:102.0) Gecko/20100101 Firefox/102.0$userAgentRandomizer")
.add("Referer", baseUrl)
// Popular Manga
@ -1041,8 +1130,70 @@ 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.isNullOrBlank()) {
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()
}
}
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"
}
}

View File

@ -10,7 +10,7 @@ class MadaraGenerator : ThemeSourceGenerator {
override val themeClass = "Madara"
override val baseVersionCode: Int = 26
override val baseVersionCode: Int = 27
override val sources = listOf(
MultiLang("Leviatan Scans", "https://leviatanscans.com", listOf("en", "es"), className = "LeviatanScansFactory", overrideVersionCode = 13),