Initial commit

This commit is contained in:
FourTOne5
2024-01-09 04:12:39 +06:00
commit 600c345dfe
8593 changed files with 150590 additions and 0 deletions

View File

@@ -0,0 +1,23 @@
plugins {
id("com.android.library")
kotlin("android")
id("kotlinx-serialization")
}
android {
compileSdk = AndroidConfig.compileSdk
defaultConfig {
minSdk = AndroidConfig.minSdk
}
namespace = "eu.kanade.tachiyomi.lib.randomua"
}
repositories {
mavenCentral()
}
dependencies {
compileOnly(libs.bundles.common)
}

View File

@@ -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>
)

View File

@@ -0,0 +1,70 @@
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
/**
* Helper function to return UserAgentType based on SharedPreference value
*/
fun SharedPreferences.getPrefUAType(): UserAgentType {
return when (getString(PREF_KEY_RANDOM_UA, "off")) {
"mobile" -> UserAgentType.MOBILE
"desktop" -> UserAgentType.DESKTOP
else -> UserAgentType.OFF
}
}
/**
* Helper function to return custom UserAgent from SharedPreference
*/
fun SharedPreferences.getPrefCustomUA(): String? {
return getString(PREF_KEY_CUSTOM_UA, null)
}
/**
* Helper function to add Random User-Agent settings to SharedPreference
*
* @param screen, PreferenceScreen from `setupPreferenceScreen`
*/
fun addRandomUAPreferenceToScreen(
screen: PreferenceScreen,
) {
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")
}.also(screen::addPreference)
EditTextPreference(screen.context).apply {
key = PREF_KEY_CUSTOM_UA
title = TITLE_CUSTOM_UA
summary = CUSTOM_UA_SUMMARY
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
}
}
}.also(screen::addPreference)
}
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 (Requires Restart)"
const val PREF_KEY_CUSTOM_UA = "pref_key_custom_ua_"
const val CUSTOM_UA_SUMMARY = "Leave blank to use application default user-agent (IGNORED if Random User-Agent is enabled)"