diff --git a/multisrc/overrides/mangathemesia/asurascans/src/AsuraScans.kt b/multisrc/overrides/mangathemesia/asurascans/src/AsuraScans.kt index ecd8a0304..865dad0cd 100644 --- a/multisrc/overrides/mangathemesia/asurascans/src/AsuraScans.kt +++ b/multisrc/overrides/mangathemesia/asurascans/src/AsuraScans.kt @@ -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 { diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mangathemesia/MangaThemesia.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mangathemesia/MangaThemesia.kt index 5841e34b3..d29b8fb2a 100644 --- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mangathemesia/MangaThemesia.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mangathemesia/MangaThemesia.kt @@ -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().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 = listOf() + protected open val filterExcludeUserAgent: List = 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>>(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" } } diff --git a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mangathemesia/MangaThemesiaGenerator.kt b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mangathemesia/MangaThemesiaGenerator.kt index 9110c2f93..2df11c91b 100644 --- a/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mangathemesia/MangaThemesiaGenerator.kt +++ b/multisrc/src/main/java/eu/kanade/tachiyomi/multisrc/mangathemesia/MangaThemesiaGenerator.kt @@ -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),