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:
parent
58a572a25f
commit
70ff14a274
|
@ -5,7 +5,6 @@ import eu.kanade.tachiyomi.network.GET
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
|
|
||||||
class AdonisFansub : Madara("Adonis Fansub", "https://manga.adonisfansub.com", "tr") {
|
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 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)
|
override fun latestUpdatesRequest(page: Int): Request = GET("$baseUrl/manga/page/$page/?m_orderby=latest", headers)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,11 @@
|
||||||
package eu.kanade.tachiyomi.extension.pt.yugenmangas
|
package eu.kanade.tachiyomi.extension.pt.yugenmangas
|
||||||
|
|
||||||
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
import eu.kanade.tachiyomi.multisrc.madara.Madara
|
||||||
import eu.kanade.tachiyomi.network.GET
|
|
||||||
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
import eu.kanade.tachiyomi.network.interceptor.rateLimit
|
||||||
import eu.kanade.tachiyomi.source.model.SChapter
|
import eu.kanade.tachiyomi.source.model.SChapter
|
||||||
import kotlinx.serialization.decodeFromString
|
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.Interceptor
|
|
||||||
import okhttp3.OkHttpClient
|
import okhttp3.OkHttpClient
|
||||||
import okhttp3.Response
|
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import java.io.IOException
|
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
@ -23,7 +18,7 @@ class YugenMangas : Madara(
|
||||||
) {
|
) {
|
||||||
|
|
||||||
override val client: OkHttpClient = super.client.newBuilder()
|
override val client: OkHttpClient = super.client.newBuilder()
|
||||||
.addInterceptor(::uaIntercept)
|
.addInterceptor(uaIntercept)
|
||||||
.rateLimit(1, 3, TimeUnit.SECONDS)
|
.rateLimit(1, 3, TimeUnit.SECONDS)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
|
@ -49,39 +44,5 @@ class YugenMangas : Madara(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private var userAgent: String? = null
|
override val useRandomUserAgentByDefault: Boolean = true
|
||||||
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"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,16 @@
|
||||||
package eu.kanade.tachiyomi.multisrc.madara
|
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.GET
|
||||||
import eu.kanade.tachiyomi.network.POST
|
import eu.kanade.tachiyomi.network.POST
|
||||||
import eu.kanade.tachiyomi.network.asObservable
|
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.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
|
||||||
|
@ -11,6 +19,7 @@ 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 kotlinx.serialization.decodeFromString
|
||||||
import kotlinx.serialization.json.Json
|
import kotlinx.serialization.json.Json
|
||||||
import kotlinx.serialization.json.jsonObject
|
import kotlinx.serialization.json.jsonObject
|
||||||
import kotlinx.serialization.json.jsonPrimitive
|
import kotlinx.serialization.json.jsonPrimitive
|
||||||
|
@ -18,38 +27,119 @@ import okhttp3.CacheControl
|
||||||
import okhttp3.FormBody
|
import okhttp3.FormBody
|
||||||
import okhttp3.Headers
|
import okhttp3.Headers
|
||||||
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull
|
||||||
|
import okhttp3.Interceptor
|
||||||
import okhttp3.OkHttpClient
|
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
|
||||||
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
|
||||||
import uy.kohesive.injekt.injectLazy
|
import uy.kohesive.injekt.injectLazy
|
||||||
|
import java.io.IOException
|
||||||
import java.text.ParseException
|
import java.text.ParseException
|
||||||
import java.text.SimpleDateFormat
|
import java.text.SimpleDateFormat
|
||||||
import java.util.Calendar
|
import java.util.Calendar
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
import kotlin.math.absoluteValue
|
|
||||||
import kotlin.random.Random
|
|
||||||
|
|
||||||
abstract class Madara(
|
abstract class Madara(
|
||||||
override val name: String,
|
override val name: String,
|
||||||
override val baseUrl: String,
|
override val baseUrl: String,
|
||||||
final override val lang: String,
|
final override val lang: String,
|
||||||
private val dateFormat: SimpleDateFormat = SimpleDateFormat("MMMM dd, yyyy", Locale.US)
|
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 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()
|
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
|
||||||
|
.addInterceptor(uaIntercept)
|
||||||
.connectTimeout(10, TimeUnit.SECONDS)
|
.connectTimeout(10, TimeUnit.SECONDS)
|
||||||
.readTimeout(30, TimeUnit.SECONDS)
|
.readTimeout(30, TimeUnit.SECONDS)
|
||||||
.build()
|
.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()
|
protected open val json: Json by injectLazy()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -79,7 +169,6 @@ abstract class Madara(
|
||||||
protected open val fetchGenres: Boolean = true
|
protected open val fetchGenres: Boolean = true
|
||||||
|
|
||||||
override fun headersBuilder(): Headers.Builder = Headers.Builder()
|
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)
|
.add("Referer", baseUrl)
|
||||||
|
|
||||||
// Popular Manga
|
// 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 {
|
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:"
|
const val URL_SEARCH_PREFIX = "slug:"
|
||||||
|
private const val UA_DB_URL = "https://tachiyomiorg.github.io/user-agents/user-agents.json"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ class MadaraGenerator : ThemeSourceGenerator {
|
||||||
|
|
||||||
override val themeClass = "Madara"
|
override val themeClass = "Madara"
|
||||||
|
|
||||||
override val baseVersionCode: Int = 26
|
override val baseVersionCode: Int = 27
|
||||||
|
|
||||||
override val sources = listOf(
|
override val sources = listOf(
|
||||||
MultiLang("Leviatan Scans", "https://leviatanscans.com", listOf("en", "es"), className = "LeviatanScansFactory", overrideVersionCode = 13),
|
MultiLang("Leviatan Scans", "https://leviatanscans.com", listOf("en", "es"), className = "LeviatanScansFactory", overrideVersionCode = 13),
|
||||||
|
|
Loading…
Reference in New Issue