mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
Merge pull request #158 from Blatzar/master
Added DNS over HTTPS and cache
This commit is contained in:
commit
12977e1788
12 changed files with 242 additions and 14 deletions
|
@ -63,6 +63,9 @@ android {
|
||||||
debuggable true
|
debuggable true
|
||||||
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
|
||||||
}
|
}
|
||||||
|
debug {
|
||||||
|
applicationIdSuffix ".debug"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
compileOptions {
|
compileOptions {
|
||||||
sourceCompatibility JavaVersion.VERSION_1_8
|
sourceCompatibility JavaVersion.VERSION_1_8
|
||||||
|
@ -106,6 +109,7 @@ dependencies {
|
||||||
|
|
||||||
implementation 'com.github.bumptech.glide:glide:4.12.0'
|
implementation 'com.github.bumptech.glide:glide:4.12.0'
|
||||||
kapt 'com.github.bumptech.glide:compiler:4.12.0'
|
kapt 'com.github.bumptech.glide:compiler:4.12.0'
|
||||||
|
implementation 'com.github.bumptech.glide:okhttp3-integration:4.12.0'
|
||||||
|
|
||||||
implementation 'jp.wasabeef:glide-transformations:4.0.0'
|
implementation 'jp.wasabeef:glide-transformations:4.0.0'
|
||||||
|
|
||||||
|
@ -141,5 +145,6 @@ dependencies {
|
||||||
implementation "androidx.work:work-runtime-ktx:2.7.0-rc01"
|
implementation "androidx.work:work-runtime-ktx:2.7.0-rc01"
|
||||||
|
|
||||||
// Networking
|
// Networking
|
||||||
implementation "com.squareup.okhttp3:okhttp:4.9.0"
|
implementation "com.squareup.okhttp3:okhttp:4.9.1"
|
||||||
|
implementation "com.squareup.okhttp3:okhttp-dnsoverhttps:4.9.1"
|
||||||
}
|
}
|
|
@ -26,6 +26,9 @@ import com.lagradost.cloudstream3.APIHolder.apis
|
||||||
import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings
|
import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings
|
||||||
import com.lagradost.cloudstream3.APIHolder.restrictedApis
|
import com.lagradost.cloudstream3.APIHolder.restrictedApis
|
||||||
import com.lagradost.cloudstream3.mvvm.logError
|
import com.lagradost.cloudstream3.mvvm.logError
|
||||||
|
import com.lagradost.cloudstream3.network.get
|
||||||
|
import com.lagradost.cloudstream3.network.initRequestClient
|
||||||
|
import com.lagradost.cloudstream3.network.text
|
||||||
import com.lagradost.cloudstream3.receivers.VideoDownloadRestartReceiver
|
import com.lagradost.cloudstream3.receivers.VideoDownloadRestartReceiver
|
||||||
import com.lagradost.cloudstream3.ui.APIRepository
|
import com.lagradost.cloudstream3.ui.APIRepository
|
||||||
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_NAVIGATE_TO
|
import com.lagradost.cloudstream3.ui.download.DOWNLOAD_NAVIGATE_TO
|
||||||
|
@ -46,6 +49,7 @@ import com.lagradost.cloudstream3.utils.UIHelper.toPx
|
||||||
import kotlinx.android.synthetic.main.activity_main.*
|
import kotlinx.android.synthetic.main.activity_main.*
|
||||||
import kotlinx.android.synthetic.main.fragment_result.*
|
import kotlinx.android.synthetic.main.fragment_result.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
import java.util.zip.GZIPInputStream
|
||||||
import kotlin.concurrent.thread
|
import kotlin.concurrent.thread
|
||||||
|
|
||||||
|
|
||||||
|
@ -290,6 +294,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
true
|
true
|
||||||
) // THEME IS SET BEFORE VIEW IS CREATED TO APPLY THE THEME TO THE MAIN VIEW
|
) // THEME IS SET BEFORE VIEW IS CREATED TO APPLY THE THEME TO THE MAIN VIEW
|
||||||
updateLocale()
|
updateLocale()
|
||||||
|
initRequestClient()
|
||||||
super.onCreate(savedInstanceState)
|
super.onCreate(savedInstanceState)
|
||||||
try {
|
try {
|
||||||
if (isCastApiAvailable()) {
|
if (isCastApiAvailable()) {
|
||||||
|
@ -334,7 +339,8 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
// Fucks up anime info layout since that has its own layout
|
// Fucks up anime info layout since that has its own layout
|
||||||
cast_mini_controller_holder?.isVisible = !listOf(R.id.navigation_results,R.id.navigation_player).contains(destination.id)
|
cast_mini_controller_holder?.isVisible =
|
||||||
|
!listOf(R.id.navigation_results, R.id.navigation_player).contains(destination.id)
|
||||||
|
|
||||||
nav_view.isVisible = listOf(
|
nav_view.isVisible = listOf(
|
||||||
R.id.navigation_home,
|
R.id.navigation_home,
|
||||||
|
|
|
@ -183,7 +183,7 @@ class TrailersToProvider : MainAPI() {
|
||||||
|
|
||||||
return isSucc
|
return isSucc
|
||||||
} else if (url.contains("/episode/")) {
|
} else if (url.contains("/episode/")) {
|
||||||
val response = get(url).text
|
val response = get(url, params = mapOf("preview" to "1")).text
|
||||||
val document = Jsoup.parse(response)
|
val document = Jsoup.parse(response)
|
||||||
// val qSub = document.select("subtitle-content")
|
// val qSub = document.select("subtitle-content")
|
||||||
val subUrl = document.select("subtitle-content")?.attr("data-url") ?: ""
|
val subUrl = document.select("subtitle-content")?.attr("data-url") ?: ""
|
||||||
|
|
|
@ -0,0 +1,67 @@
|
||||||
|
package com.lagradost.cloudstream3.network
|
||||||
|
|
||||||
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.dnsoverhttps.DnsOverHttps
|
||||||
|
import java.net.InetAddress
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Based on https://github.com/tachiyomiorg/tachiyomi/blob/master/app/src/main/java/eu/kanade/tachiyomi/network/DohProviders.kt
|
||||||
|
*/
|
||||||
|
|
||||||
|
fun OkHttpClient.Builder.addGenericDns(url: String, ips: List<String>) = dns(
|
||||||
|
DnsOverHttps
|
||||||
|
.Builder()
|
||||||
|
.client(build())
|
||||||
|
.url(url.toHttpUrl())
|
||||||
|
.bootstrapDnsHosts(
|
||||||
|
ips.map { InetAddress.getByName(it) }
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
)
|
||||||
|
|
||||||
|
fun OkHttpClient.Builder.addGoogleDns() = (
|
||||||
|
addGenericDns(
|
||||||
|
"https://dns.google/dns-query",
|
||||||
|
listOf(
|
||||||
|
"8.8.4.4",
|
||||||
|
"8.8.8.8"
|
||||||
|
)
|
||||||
|
))
|
||||||
|
|
||||||
|
fun OkHttpClient.Builder.addCloudFlareDns() = (
|
||||||
|
addGenericDns(
|
||||||
|
"https://cloudflare-dns.com/dns-query",
|
||||||
|
// https://www.cloudflare.com/ips/
|
||||||
|
listOf(
|
||||||
|
"1.1.1.1",
|
||||||
|
"1.0.0.1",
|
||||||
|
"2606:4700:4700::1111",
|
||||||
|
"2606:4700:4700::1001"
|
||||||
|
)
|
||||||
|
))
|
||||||
|
|
||||||
|
// Commented out as it doesn't work
|
||||||
|
//fun OkHttpClient.Builder.addOpenDns() = (
|
||||||
|
// addGenericDns(
|
||||||
|
// "https://doh.opendns.com/dns-query",
|
||||||
|
// // https://support.opendns.com/hc/en-us/articles/360038086532-Using-DNS-over-HTTPS-DoH-with-OpenDNS
|
||||||
|
// listOf(
|
||||||
|
// "208.67.222.222",
|
||||||
|
// "208.67.220.220",
|
||||||
|
// "2620:119:35::35",
|
||||||
|
// "2620:119:53::53",
|
||||||
|
// )
|
||||||
|
// ))
|
||||||
|
|
||||||
|
|
||||||
|
fun OkHttpClient.Builder.addAdGuardDns() = (
|
||||||
|
addGenericDns(
|
||||||
|
"https://dns.adguard.com/dns-query",
|
||||||
|
// https://github.com/AdguardTeam/AdGuardDNS
|
||||||
|
listOf(
|
||||||
|
// "Non-filtering"
|
||||||
|
"94.140.14.140",
|
||||||
|
"94.140.14.141",
|
||||||
|
)
|
||||||
|
))
|
|
@ -1,12 +1,20 @@
|
||||||
package com.lagradost.cloudstream3.network
|
package com.lagradost.cloudstream3.network
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import androidx.preference.PreferenceManager
|
||||||
|
import com.lagradost.cloudstream3.R
|
||||||
import com.lagradost.cloudstream3.USER_AGENT
|
import com.lagradost.cloudstream3.USER_AGENT
|
||||||
import okhttp3.*
|
import okhttp3.*
|
||||||
import okhttp3.Headers.Companion.toHeaders
|
import okhttp3.Headers.Companion.toHeaders
|
||||||
|
import okhttp3.HttpUrl.Companion.toHttpUrl
|
||||||
|
import okhttp3.dnsoverhttps.DnsOverHttps
|
||||||
|
import java.io.File
|
||||||
|
import java.net.InetAddress
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
var baseClient = OkHttpClient()
|
||||||
private const val DEFAULT_TIME = 10
|
private const val DEFAULT_TIME = 10
|
||||||
private val DEFAULT_TIME_UNIT = TimeUnit.MINUTES
|
private val DEFAULT_TIME_UNIT = TimeUnit.MINUTES
|
||||||
private const val DEFAULT_USER_AGENT = USER_AGENT
|
private const val DEFAULT_USER_AGENT = USER_AGENT
|
||||||
|
@ -15,6 +23,29 @@ private val DEFAULT_DATA: Map<String, String> = mapOf()
|
||||||
private val DEFAULT_COOKIES: Map<String, String> = mapOf()
|
private val DEFAULT_COOKIES: Map<String, String> = mapOf()
|
||||||
private val DEFAULT_REFERER: String? = null
|
private val DEFAULT_REFERER: String? = null
|
||||||
|
|
||||||
|
fun Context.initRequestClient(): OkHttpClient {
|
||||||
|
val settingsManager = PreferenceManager.getDefaultSharedPreferences(this)
|
||||||
|
val dns = settingsManager.getInt(this.getString(R.string.dns_pref), 0)
|
||||||
|
baseClient = OkHttpClient.Builder()
|
||||||
|
.cache(
|
||||||
|
// Note that you need to add a ResponseInterceptor to make this 100% active.
|
||||||
|
// The server response dictates if and when stuff should be cached.
|
||||||
|
Cache(
|
||||||
|
directory = File(cacheDir, "http_cache"),
|
||||||
|
maxSize = 50L * 1024L * 1024L // 50 MiB
|
||||||
|
)
|
||||||
|
).apply {
|
||||||
|
when (dns) {
|
||||||
|
1 -> addGoogleDns()
|
||||||
|
2 -> addCloudFlareDns()
|
||||||
|
// 3 -> addOpenDns()
|
||||||
|
4 -> addAdGuardDns()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Needs to be build as otherwise the other builders will change this object
|
||||||
|
.build()
|
||||||
|
return baseClient
|
||||||
|
}
|
||||||
|
|
||||||
/** WARNING! CAN ONLY BE READ ONCE */
|
/** WARNING! CAN ONLY BE READ ONCE */
|
||||||
val Response.text: String
|
val Response.text: String
|
||||||
|
@ -93,14 +124,13 @@ fun get(
|
||||||
timeout: Long = 0L,
|
timeout: Long = 0L,
|
||||||
interceptor: Interceptor? = null
|
interceptor: Interceptor? = null
|
||||||
): Response {
|
): Response {
|
||||||
|
val client = baseClient
|
||||||
val client = OkHttpClient().newBuilder()
|
.newBuilder()
|
||||||
.followRedirects(allowRedirects)
|
.followRedirects(allowRedirects)
|
||||||
.followSslRedirects(allowRedirects)
|
.followSslRedirects(allowRedirects)
|
||||||
.callTimeout(timeout, TimeUnit.SECONDS)
|
.callTimeout(timeout, TimeUnit.SECONDS)
|
||||||
|
|
||||||
if (interceptor != null) client.addInterceptor(interceptor)
|
if (interceptor != null) client.addInterceptor(interceptor)
|
||||||
|
|
||||||
val request = getRequestCreator(url, headers, referer, params, cookies, cacheTime, cacheUnit)
|
val request = getRequestCreator(url, headers, referer, params, cookies, cacheTime, cacheUnit)
|
||||||
return client.build().newCall(request).execute()
|
return client.build().newCall(request).execute()
|
||||||
}
|
}
|
||||||
|
@ -118,7 +148,8 @@ fun post(
|
||||||
cacheUnit: TimeUnit = DEFAULT_TIME_UNIT,
|
cacheUnit: TimeUnit = DEFAULT_TIME_UNIT,
|
||||||
timeout: Long = 0L
|
timeout: Long = 0L
|
||||||
): Response {
|
): Response {
|
||||||
val client = OkHttpClient().newBuilder()
|
val client = baseClient
|
||||||
|
.newBuilder()
|
||||||
.followRedirects(allowRedirects)
|
.followRedirects(allowRedirects)
|
||||||
.followSslRedirects(allowRedirects)
|
.followSslRedirects(allowRedirects)
|
||||||
.callTimeout(timeout, TimeUnit.SECONDS)
|
.callTimeout(timeout, TimeUnit.SECONDS)
|
||||||
|
|
|
@ -3,6 +3,7 @@ package com.lagradost.cloudstream3.network
|
||||||
import android.annotation.SuppressLint
|
import android.annotation.SuppressLint
|
||||||
import android.net.http.SslError
|
import android.net.http.SslError
|
||||||
import android.webkit.*
|
import android.webkit.*
|
||||||
|
import androidx.core.view.contains
|
||||||
import com.lagradost.cloudstream3.AcraApplication
|
import com.lagradost.cloudstream3.AcraApplication
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
|
@ -10,6 +11,7 @@ import kotlinx.coroutines.runBlocking
|
||||||
import okhttp3.Interceptor
|
import okhttp3.Interceptor
|
||||||
import okhttp3.Request
|
import okhttp3.Request
|
||||||
import okhttp3.Response
|
import okhttp3.Response
|
||||||
|
import java.net.URI
|
||||||
import java.util.concurrent.TimeUnit
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
class WebViewResolver(val interceptUrl: Regex) : Interceptor {
|
class WebViewResolver(val interceptUrl: Regex) : Interceptor {
|
||||||
|
@ -56,7 +58,7 @@ class WebViewResolver(val interceptUrl: Regex) : Interceptor {
|
||||||
request: WebResourceRequest
|
request: WebResourceRequest
|
||||||
): WebResourceResponse? {
|
): WebResourceResponse? {
|
||||||
val webViewUrl = request.url.toString()
|
val webViewUrl = request.url.toString()
|
||||||
// println("Override url $webViewUrl")
|
|
||||||
if (interceptUrl.containsMatchIn(webViewUrl)) {
|
if (interceptUrl.containsMatchIn(webViewUrl)) {
|
||||||
fixedRequest = getRequestCreator(
|
fixedRequest = getRequestCreator(
|
||||||
webViewUrl,
|
webViewUrl,
|
||||||
|
@ -71,7 +73,27 @@ class WebViewResolver(val interceptUrl: Regex) : Interceptor {
|
||||||
println("Web-view request finished: $webViewUrl")
|
println("Web-view request finished: $webViewUrl")
|
||||||
destroyWebView()
|
destroyWebView()
|
||||||
}
|
}
|
||||||
return super.shouldInterceptRequest(view, request)
|
|
||||||
|
return try {
|
||||||
|
when {
|
||||||
|
// suppress favicon requests as we don't display them anywhere
|
||||||
|
webViewUrl.endsWith("/favicon.ico") -> WebResourceResponse("image/png", null, null)
|
||||||
|
webViewUrl.contains("recaptcha") -> super.shouldInterceptRequest(view, request)
|
||||||
|
|
||||||
|
request.method == "GET" -> get(
|
||||||
|
webViewUrl,
|
||||||
|
headers = request.requestHeaders
|
||||||
|
).toWebResourceResponse()
|
||||||
|
|
||||||
|
request.method == "POST" -> post(
|
||||||
|
webViewUrl,
|
||||||
|
headers = request.requestHeaders
|
||||||
|
).toWebResourceResponse()
|
||||||
|
else -> return super.shouldInterceptRequest(view, request)
|
||||||
|
}
|
||||||
|
} catch (e: Exception) {
|
||||||
|
null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onReceivedSslError(view: WebView?, handler: SslErrorHandler?, error: SslError?) {
|
override fun onReceivedSslError(view: WebView?, handler: SslErrorHandler?, error: SslError?) {
|
||||||
|
@ -99,4 +121,18 @@ class WebViewResolver(val interceptUrl: Regex) : Interceptor {
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun Response.toWebResourceResponse(): WebResourceResponse {
|
||||||
|
val contentTypeValue = this.header("Content-Type")
|
||||||
|
// 1. contentType. 2. charset
|
||||||
|
val typeRegex = Regex("""(.*);(?:.*charset=(.*)(?:|;)|)""")
|
||||||
|
return if (contentTypeValue != null) {
|
||||||
|
val found = typeRegex.find(contentTypeValue ?: "")
|
||||||
|
val contentType = found?.groupValues?.getOrNull(1)?.ifBlank { null } ?: contentTypeValue
|
||||||
|
val charset = found?.groupValues?.getOrNull(2)?.ifBlank { null }
|
||||||
|
WebResourceResponse(contentType, charset, this.body?.byteStream())
|
||||||
|
} else {
|
||||||
|
WebResourceResponse("application/octet-stream", null, this.body?.byteStream())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -16,6 +16,7 @@ import com.lagradost.cloudstream3.MainActivity.Companion.setLocale
|
||||||
import com.lagradost.cloudstream3.MainActivity.Companion.showToast
|
import com.lagradost.cloudstream3.MainActivity.Companion.showToast
|
||||||
import com.lagradost.cloudstream3.R
|
import com.lagradost.cloudstream3.R
|
||||||
import com.lagradost.cloudstream3.mvvm.logError
|
import com.lagradost.cloudstream3.mvvm.logError
|
||||||
|
import com.lagradost.cloudstream3.network.initRequestClient
|
||||||
import com.lagradost.cloudstream3.ui.APIRepository
|
import com.lagradost.cloudstream3.ui.APIRepository
|
||||||
import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment
|
import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment
|
||||||
import com.lagradost.cloudstream3.utils.InAppUpdater.Companion.runAutoUpdate
|
import com.lagradost.cloudstream3.utils.InAppUpdater.Companion.runAutoUpdate
|
||||||
|
@ -53,6 +54,7 @@ class SettingsFragment : PreferenceFragmentCompat() {
|
||||||
val localePreference = findPreference<Preference>(getString(R.string.locale_key))!!
|
val localePreference = findPreference<Preference>(getString(R.string.locale_key))!!
|
||||||
val benenePreference = findPreference<Preference>(getString(R.string.benene_count))!!
|
val benenePreference = findPreference<Preference>(getString(R.string.benene_count))!!
|
||||||
val watchQualityPreference = findPreference<Preference>(getString(R.string.quality_pref_key))!!
|
val watchQualityPreference = findPreference<Preference>(getString(R.string.quality_pref_key))!!
|
||||||
|
val dnsPreference = findPreference<Preference>(getString(R.string.dns_key))!!
|
||||||
val legalPreference = findPreference<Preference>(getString(R.string.legal_notice_key))!!
|
val legalPreference = findPreference<Preference>(getString(R.string.legal_notice_key))!!
|
||||||
val subdubPreference = findPreference<Preference>(getString(R.string.display_sub_key))!!
|
val subdubPreference = findPreference<Preference>(getString(R.string.display_sub_key))!!
|
||||||
val providerLangPreference = findPreference<Preference>(getString(R.string.provider_lang_key))!!
|
val providerLangPreference = findPreference<Preference>(getString(R.string.provider_lang_key))!!
|
||||||
|
@ -154,6 +156,25 @@ class SettingsFragment : PreferenceFragmentCompat() {
|
||||||
return@setOnPreferenceClickListener true
|
return@setOnPreferenceClickListener true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dnsPreference.setOnPreferenceClickListener {
|
||||||
|
val prefNames = resources.getStringArray(R.array.dns_pref)
|
||||||
|
val prefValues = resources.getIntArray(R.array.dns_pref_values)
|
||||||
|
val settingsManager = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
|
||||||
|
val currentDns =
|
||||||
|
settingsManager.getInt(getString(R.string.dns_pref), 0)
|
||||||
|
context?.showBottomDialog(
|
||||||
|
prefNames.toList(),
|
||||||
|
prefValues.indexOf(currentDns),
|
||||||
|
getString(R.string.dns_pref),
|
||||||
|
true,
|
||||||
|
{}) {
|
||||||
|
settingsManager.edit().putInt(getString(R.string.dns_pref), prefValues[it]).apply()
|
||||||
|
context?.initRequestClient()
|
||||||
|
}
|
||||||
|
return@setOnPreferenceClickListener true
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
val settingsManager = PreferenceManager.getDefaultSharedPreferences(context)
|
val settingsManager = PreferenceManager.getDefaultSharedPreferences(context)
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,18 @@
|
||||||
package com.lagradost.cloudstream3.utils
|
package com.lagradost.cloudstream3.utils
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import com.bumptech.glide.Glide
|
||||||
import com.bumptech.glide.GlideBuilder
|
import com.bumptech.glide.GlideBuilder
|
||||||
|
import com.bumptech.glide.Registry
|
||||||
import com.bumptech.glide.annotation.GlideModule
|
import com.bumptech.glide.annotation.GlideModule
|
||||||
|
import com.bumptech.glide.integration.okhttp3.OkHttpUrlLoader
|
||||||
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
import com.bumptech.glide.load.engine.DiskCacheStrategy
|
||||||
|
import com.bumptech.glide.load.model.GlideUrl
|
||||||
import com.bumptech.glide.module.AppGlideModule
|
import com.bumptech.glide.module.AppGlideModule
|
||||||
import com.bumptech.glide.request.RequestOptions
|
import com.bumptech.glide.request.RequestOptions
|
||||||
import com.bumptech.glide.signature.ObjectKey
|
import com.bumptech.glide.signature.ObjectKey
|
||||||
|
import com.lagradost.cloudstream3.network.initRequestClient
|
||||||
|
import java.io.InputStream
|
||||||
|
|
||||||
@GlideModule
|
@GlideModule
|
||||||
class GlideModule : AppGlideModule() {
|
class GlideModule : AppGlideModule() {
|
||||||
|
@ -18,4 +24,16 @@ class GlideModule : AppGlideModule() {
|
||||||
.signature(ObjectKey(System.currentTimeMillis().toShort()))
|
.signature(ObjectKey(System.currentTimeMillis().toShort()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Needed for DOH
|
||||||
|
// https://stackoverflow.com/a/61634041
|
||||||
|
override fun registerComponents(context: Context, glide: Glide, registry: Registry) {
|
||||||
|
val client = context.initRequestClient()
|
||||||
|
registry.replace(
|
||||||
|
GlideUrl::class.java,
|
||||||
|
InputStream::class.java,
|
||||||
|
OkHttpUrlLoader.Factory(client)
|
||||||
|
)
|
||||||
|
super.registerComponents(context, glide, registry)
|
||||||
|
}
|
||||||
}
|
}
|
10
app/src/main/res/drawable/ic_baseline_dns_24.xml
Normal file
10
app/src/main/res/drawable/ic_baseline_dns_24.xml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="@color/white">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M20,13H4c-0.55,0 -1,0.45 -1,1v6c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1v-6c0,-0.55 -0.45,-1 -1,-1zM7,19c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2zM20,3H4c-0.55,0 -1,0.45 -1,1v6c0,0.55 0.45,1 1,1h16c0.55,0 1,-0.45 1,-1V4c0,-0.55 -0.45,-1 -1,-1zM7,9c-1.1,0 -2,-0.9 -2,-2s0.9,-2 2,-2 2,0.9 2,2 -0.9,2 -2,2z"/>
|
||||||
|
</vector>
|
|
@ -31,6 +31,21 @@
|
||||||
<item>-2</item>
|
<item>-2</item>
|
||||||
</array>
|
</array>
|
||||||
|
|
||||||
|
<array name="dns_pref">
|
||||||
|
<item>None</item>
|
||||||
|
<item>Google</item>
|
||||||
|
<item>Cloudflare</item>
|
||||||
|
<!-- <item>OpenDns</item>-->
|
||||||
|
<item>AdGuard</item>
|
||||||
|
</array>
|
||||||
|
<array name="dns_pref_values">
|
||||||
|
<item>0</item>
|
||||||
|
<item>1</item>
|
||||||
|
<item>2</item>
|
||||||
|
<!-- <item>3</item>-->
|
||||||
|
<item>4</item>
|
||||||
|
</array>
|
||||||
|
|
||||||
<array name="episode_long_click_options">
|
<array name="episode_long_click_options">
|
||||||
<item>@string/episode_action_chomecast_episode</item>
|
<item>@string/episode_action_chomecast_episode</item>
|
||||||
<item>@string/episode_action_chomecast_mirror</item>
|
<item>@string/episode_action_chomecast_mirror</item>
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
<string name="display_sub_key" translatable="false">display_sub_key</string>
|
<string name="display_sub_key" translatable="false">display_sub_key</string>
|
||||||
<string name="show_fillers_key" translatable="false">show_fillers_key</string>
|
<string name="show_fillers_key" translatable="false">show_fillers_key</string>
|
||||||
<string name="provider_lang_key" translatable="false">provider_lang_key</string>
|
<string name="provider_lang_key" translatable="false">provider_lang_key</string>
|
||||||
|
<string name="dns_key" translatable="false">dns_key</string>
|
||||||
|
|
||||||
|
|
||||||
<!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->
|
<!-- FORMAT MIGHT TRANSLATE, WILL CAUSE CRASH IF APPLIED WRONG -->
|
||||||
|
@ -166,7 +167,9 @@
|
||||||
<string name="double_tap_to_seek_settings_des">Tap twice on the right or left side to seek forwards or backwards
|
<string name="double_tap_to_seek_settings_des">Tap twice on the right or left side to seek forwards or backwards
|
||||||
</string>
|
</string>
|
||||||
<string name="use_system_brightness_settings">Use system brightness</string>
|
<string name="use_system_brightness_settings">Use system brightness</string>
|
||||||
<string name="use_system_brightness_settings_des">Use system brightness in the app player instead of an dark overlay</string>
|
<string name="use_system_brightness_settings_des">Use system brightness in the app player instead of an dark
|
||||||
|
overlay
|
||||||
|
</string>
|
||||||
|
|
||||||
<string name="search">Search</string>
|
<string name="search">Search</string>
|
||||||
<string name="settings_info">Info</string>
|
<string name="settings_info">Info</string>
|
||||||
|
@ -261,6 +264,10 @@
|
||||||
<string name="dont_show_again">Don\'t show again</string>
|
<string name="dont_show_again">Don\'t show again</string>
|
||||||
<string name="update">Update</string>
|
<string name="update">Update</string>
|
||||||
<string name="watch_quality_pref">Preferred watch quality</string>
|
<string name="watch_quality_pref">Preferred watch quality</string>
|
||||||
|
<string name="dns_pref">DNS over HTTPS</string>
|
||||||
|
<string name="dns_pref_summary">Useful for bypassing ISP blocks</string>
|
||||||
|
|
||||||
|
|
||||||
<string name="display_subbed_dubbed_settings">Display Dubbed/Subbed Anime</string>
|
<string name="display_subbed_dubbed_settings">Display Dubbed/Subbed Anime</string>
|
||||||
|
|
||||||
<string name="resize_fit">Fit to screen</string>
|
<string name="resize_fit">Fit to screen</string>
|
||||||
|
@ -269,15 +276,21 @@
|
||||||
|
|
||||||
<string name="legal_notice" translatable="false">Disclaimer</string>
|
<string name="legal_notice" translatable="false">Disclaimer</string>
|
||||||
<string name="legal_notice_key" translatable="false">legal_notice_key</string>
|
<string name="legal_notice_key" translatable="false">legal_notice_key</string>
|
||||||
<string name="legal_notice_text" translatable="false">Any legal issues regarding the content on this application should be taken up with the actual file hosts and providers themselves as we are not affiliated with them.
|
<string name="legal_notice_text" translatable="false">Any legal issues regarding the content on this application
|
||||||
|
should be taken up with the actual file hosts and providers themselves as we are not affiliated with them.
|
||||||
|
|
||||||
In case of copyright infringement, please directly contact the responsible parties or the streaming websites.
|
In case of copyright infringement, please directly contact the responsible parties or the streaming websites.
|
||||||
|
|
||||||
The app is purely for educational and personal use.
|
The app is purely for educational and personal use.
|
||||||
|
|
||||||
CloudStream 3 does not host any content on the app, and has no control over what media is put up or taken down. CloudStream 3 functions like any other search engine, such as Google. CloudStream 3 does not host, upload or manage any videos, films or content. It simply crawls, aggregates and displayes links in a convenient, user-friendly interface.
|
CloudStream 3 does not host any content on the app, and has no control over what media is put up or taken down.
|
||||||
|
CloudStream 3 functions like any other search engine, such as Google. CloudStream 3 does not host, upload or
|
||||||
|
manage any videos, films or content. It simply crawls, aggregates and displayes links in a convenient,
|
||||||
|
user-friendly interface.
|
||||||
|
|
||||||
It merely scrapes 3rd-party websites that are publicly accessable via any regular web browser. It is the responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use CloudStream 3 at your own risk.
|
It merely scrapes 3rd-party websites that are publicly accessable via any regular web browser. It is the
|
||||||
|
responsibility of user to avoid any actions that might violate the laws governing his/her locality. Use
|
||||||
|
CloudStream 3 at your own risk.
|
||||||
</string>
|
</string>
|
||||||
<string name="general">General</string>
|
<string name="general">General</string>
|
||||||
<string name="provider_lang_settings">Provider Languages</string>
|
<string name="provider_lang_settings">Provider Languages</string>
|
||||||
|
|
|
@ -93,6 +93,12 @@
|
||||||
android:icon="@drawable/ic_baseline_skip_next_24"
|
android:icon="@drawable/ic_baseline_skip_next_24"
|
||||||
android:title="@string/show_fillers_settings"
|
android:title="@string/show_fillers_settings"
|
||||||
android:defaultValue="true"/>
|
android:defaultValue="true"/>
|
||||||
|
<Preference
|
||||||
|
android:key="@string/dns_key"
|
||||||
|
android:title="@string/dns_pref"
|
||||||
|
android:summary="@string/dns_pref_summary"
|
||||||
|
android:icon="@drawable/ic_baseline_dns_24">
|
||||||
|
</Preference>
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
<PreferenceCategory
|
<PreferenceCategory
|
||||||
android:key="search"
|
android:key="search"
|
||||||
|
|
Loading…
Reference in a new issue