MangaThemesia: Add support for custom and random user agent (#15512)

* MangaThemesia: Added support for custom and random user agent

* Only support extensions that will benefit from custom and random user agent

* Fixed typo in comment

* Better phrasing in the comment
This commit is contained in:
Dani de Vaal 2023-03-01 16:20:55 +01:00 committed by GitHub
parent 00b4b3a626
commit d09671ecdd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 159 additions and 2 deletions

View File

@ -34,6 +34,7 @@ open class AsuraScans(
}
override val client: OkHttpClient = network.cloudflareClient.newBuilder()
.addInterceptor(uaIntercept)
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.rateLimit(1, 3, TimeUnit.SECONDS)
@ -86,7 +87,9 @@ open class AsuraScans(
.commit()
}
}
screen.addPreference(permanentMangaUrlPref)
addRandomAndCustomUserAgentPreferences(screen)
}
private fun getPermanentMangaUrlPreferenceKey(): String {

View File

@ -1,7 +1,15 @@
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.network.GET
import eu.kanade.tachiyomi.network.POST
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
@ -10,6 +18,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.jsonArray
import kotlinx.serialization.json.jsonPrimitive
@ -17,6 +26,7 @@ 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
@ -24,7 +34,10 @@ import org.jsoup.nodes.Document
import org.jsoup.nodes.Element
import org.jsoup.select.Elements
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
@ -37,13 +50,88 @@ abstract class MangaThemesia(
override val lang: String,
val mangaUrlDirectory: String = "/manga",
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)
}
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)
.connectTimeout(10, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.build()
@ -477,6 +565,61 @@ 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)
}
companion object {
const val URL_SEARCH_PREFIX = "url:"
@ -486,5 +629,16 @@ 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"
}
}

View File

@ -11,7 +11,7 @@ class MangaThemesiaGenerator : ThemeSourceGenerator {
override val themeClass = "MangaThemesia"
override val baseVersionCode: Int = 24
override val baseVersionCode: Int = 25
override val sources = listOf(
MultiLang("Asura Scans", "https://www.asurascans.com", listOf("en", "tr"), className = "AsuraScansFactory", pkgName = "asurascans", overrideVersionCode = 18),