From b8195f2ec6d6b0d7cff4aa1b5b8196e95baab400 Mon Sep 17 00:00:00 2001 From: Blatzar <46196380+Blatzar@users.noreply.github.com> Date: Mon, 18 Oct 2021 16:02:05 +0200 Subject: [PATCH 1/2] added DOH and Cache + fixed trailers for series --- app/build.gradle | 6 +- .../lagradost/cloudstream3/MainActivity.kt | 10 ++- .../movieproviders/TrailersToProvider.kt | 2 +- .../cloudstream3/network/DohProviders.kt | 67 +++++++++++++++++++ .../cloudstream3/network/Requests.kt | 38 +++++++++-- .../ui/settings/SettingsFragment.kt | 21 ++++++ .../main/res/drawable/ic_baseline_dns_24.xml | 10 +++ app/src/main/res/values/array.xml | 15 +++++ app/src/main/res/values/strings.xml | 21 ++++-- app/src/main/res/xml/settings.xml | 6 ++ 10 files changed, 184 insertions(+), 12 deletions(-) create mode 100644 app/src/main/java/com/lagradost/cloudstream3/network/DohProviders.kt create mode 100644 app/src/main/res/drawable/ic_baseline_dns_24.xml diff --git a/app/build.gradle b/app/build.gradle index 91c3d989..1e69b78a 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -63,6 +63,9 @@ android { debuggable true proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' } + debug { + applicationIdSuffix ".debug" + } } compileOptions { sourceCompatibility JavaVersion.VERSION_1_8 @@ -141,5 +144,6 @@ dependencies { implementation "androidx.work:work-runtime-ktx:2.7.0-rc01" // 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" } \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt index d1b01c48..78a3e923 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/MainActivity.kt @@ -26,6 +26,9 @@ import com.lagradost.cloudstream3.APIHolder.apis import com.lagradost.cloudstream3.APIHolder.getApiDubstatusSettings import com.lagradost.cloudstream3.APIHolder.restrictedApis 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.ui.APIRepository 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.fragment_result.* import java.util.* +import java.util.zip.GZIPInputStream import kotlin.concurrent.thread @@ -135,7 +139,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { } companion object { - fun Activity?.getCastSession() : CastSession? { + fun Activity?.getCastSession(): CastSession? { return (this as MainActivity?)?.mSessionManager?.currentCastSession } @@ -290,6 +294,7 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { true ) // THEME IS SET BEFORE VIEW IS CREATED TO APPLY THE THEME TO THE MAIN VIEW updateLocale() + initRequestClient() super.onCreate(savedInstanceState) try { if (isCastApiAvailable()) { @@ -334,7 +339,8 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener { }*/ // 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( R.id.navigation_home, diff --git a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/TrailersToProvider.kt b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/TrailersToProvider.kt index a15d3053..ac7a3d1a 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/movieproviders/TrailersToProvider.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/movieproviders/TrailersToProvider.kt @@ -183,7 +183,7 @@ class TrailersToProvider : MainAPI() { return isSucc } 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 qSub = document.select("subtitle-content") val subUrl = document.select("subtitle-content")?.attr("data-url") ?: "" diff --git a/app/src/main/java/com/lagradost/cloudstream3/network/DohProviders.kt b/app/src/main/java/com/lagradost/cloudstream3/network/DohProviders.kt new file mode 100644 index 00000000..8a865125 --- /dev/null +++ b/app/src/main/java/com/lagradost/cloudstream3/network/DohProviders.kt @@ -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 + */ + +private fun OkHttpClient.Builder.addGenericDns(url: String, ips: List) = 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", + ) + )) \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/network/Requests.kt b/app/src/main/java/com/lagradost/cloudstream3/network/Requests.kt index 41e8b69a..b1f0c2d6 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/network/Requests.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/network/Requests.kt @@ -1,12 +1,20 @@ 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 okhttp3.* 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.util.* import java.util.concurrent.TimeUnit +var baseClient = OkHttpClient() private const val DEFAULT_TIME = 10 private val DEFAULT_TIME_UNIT = TimeUnit.MINUTES private const val DEFAULT_USER_AGENT = USER_AGENT @@ -15,6 +23,28 @@ private val DEFAULT_DATA: Map = mapOf() private val DEFAULT_COOKIES: Map = mapOf() private val DEFAULT_REFERER: String? = null +fun Context.initRequestClient() { + 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() +} /** WARNING! CAN ONLY BE READ ONCE */ val Response.text: String @@ -93,14 +123,13 @@ fun get( timeout: Long = 0L, interceptor: Interceptor? = null ): Response { - - val client = OkHttpClient().newBuilder() + val client = baseClient + .newBuilder() .followRedirects(allowRedirects) .followSslRedirects(allowRedirects) .callTimeout(timeout, TimeUnit.SECONDS) if (interceptor != null) client.addInterceptor(interceptor) - val request = getRequestCreator(url, headers, referer, params, cookies, cacheTime, cacheUnit) return client.build().newCall(request).execute() } @@ -118,7 +147,8 @@ fun post( cacheUnit: TimeUnit = DEFAULT_TIME_UNIT, timeout: Long = 0L ): Response { - val client = OkHttpClient().newBuilder() + val client = baseClient + .newBuilder() .followRedirects(allowRedirects) .followSslRedirects(allowRedirects) .callTimeout(timeout, TimeUnit.SECONDS) diff --git a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsFragment.kt b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsFragment.kt index 89525ce7..6940ba4d 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsFragment.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/ui/settings/SettingsFragment.kt @@ -16,6 +16,7 @@ import com.lagradost.cloudstream3.MainActivity.Companion.setLocale import com.lagradost.cloudstream3.MainActivity.Companion.showToast import com.lagradost.cloudstream3.R import com.lagradost.cloudstream3.mvvm.logError +import com.lagradost.cloudstream3.network.initRequestClient import com.lagradost.cloudstream3.ui.APIRepository import com.lagradost.cloudstream3.ui.subtitles.SubtitlesFragment import com.lagradost.cloudstream3.utils.InAppUpdater.Companion.runAutoUpdate @@ -53,6 +54,7 @@ class SettingsFragment : PreferenceFragmentCompat() { val localePreference = findPreference(getString(R.string.locale_key))!! val benenePreference = findPreference(getString(R.string.benene_count))!! val watchQualityPreference = findPreference(getString(R.string.quality_pref_key))!! + val dnsPreference = findPreference(getString(R.string.dns_key))!! val legalPreference = findPreference(getString(R.string.legal_notice_key))!! val subdubPreference = findPreference(getString(R.string.display_sub_key))!! val providerLangPreference = findPreference(getString(R.string.provider_lang_key))!! @@ -154,6 +156,25 @@ class SettingsFragment : PreferenceFragmentCompat() { 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 { val settingsManager = PreferenceManager.getDefaultSharedPreferences(context) diff --git a/app/src/main/res/drawable/ic_baseline_dns_24.xml b/app/src/main/res/drawable/ic_baseline_dns_24.xml new file mode 100644 index 00000000..b2677f76 --- /dev/null +++ b/app/src/main/res/drawable/ic_baseline_dns_24.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/values/array.xml b/app/src/main/res/values/array.xml index febfea2d..c2a1504f 100644 --- a/app/src/main/res/values/array.xml +++ b/app/src/main/res/values/array.xml @@ -31,6 +31,21 @@ -2 + + None + Google + Cloudflare + + AdGuard + + + 0 + 1 + 2 + + 4 + + @string/episode_action_chomecast_episode @string/episode_action_chomecast_mirror diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index cfc00ecd..e057a0f3 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -23,6 +23,7 @@ display_sub_key show_fillers_key provider_lang_key + dns_key @@ -166,7 +167,9 @@ Tap twice on the right or left side to seek forwards or backwards Use system brightness - Use system brightness in the app player instead of an dark overlay + Use system brightness in the app player instead of an dark + overlay + Search Info @@ -261,6 +264,10 @@ Don\'t show again Update Preferred watch quality + DNS over HTTPS + Useful for bypassing ISP blocks + + Display Dubbed/Subbed Anime Fit to screen @@ -269,15 +276,21 @@ Disclaimer legal_notice_key - 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. + 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. 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. General Provider Languages diff --git a/app/src/main/res/xml/settings.xml b/app/src/main/res/xml/settings.xml index 1bdbce6c..c866a536 100644 --- a/app/src/main/res/xml/settings.xml +++ b/app/src/main/res/xml/settings.xml @@ -93,6 +93,12 @@ android:icon="@drawable/ic_baseline_skip_next_24" android:title="@string/show_fillers_settings" android:defaultValue="true"/> + + Date: Mon, 18 Oct 2021 18:04:05 +0200 Subject: [PATCH 2/2] fixed doh for webview and glide --- app/build.gradle | 1 + .../cloudstream3/network/DohProviders.kt | 2 +- .../cloudstream3/network/Requests.kt | 3 +- .../cloudstream3/network/WebViewResolver.kt | 40 ++++++++++++++++++- .../lagradost/cloudstream3/utils/GlideApp.kt | 18 +++++++++ 5 files changed, 60 insertions(+), 4 deletions(-) diff --git a/app/build.gradle b/app/build.gradle index 1e69b78a..1f52cb85 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -109,6 +109,7 @@ dependencies { implementation 'com.github.bumptech.glide:glide: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' diff --git a/app/src/main/java/com/lagradost/cloudstream3/network/DohProviders.kt b/app/src/main/java/com/lagradost/cloudstream3/network/DohProviders.kt index 8a865125..65f1a49d 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/network/DohProviders.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/network/DohProviders.kt @@ -9,7 +9,7 @@ import java.net.InetAddress * Based on https://github.com/tachiyomiorg/tachiyomi/blob/master/app/src/main/java/eu/kanade/tachiyomi/network/DohProviders.kt */ -private fun OkHttpClient.Builder.addGenericDns(url: String, ips: List) = dns( + fun OkHttpClient.Builder.addGenericDns(url: String, ips: List) = dns( DnsOverHttps .Builder() .client(build()) diff --git a/app/src/main/java/com/lagradost/cloudstream3/network/Requests.kt b/app/src/main/java/com/lagradost/cloudstream3/network/Requests.kt index b1f0c2d6..7934e647 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/network/Requests.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/network/Requests.kt @@ -23,7 +23,7 @@ private val DEFAULT_DATA: Map = mapOf() private val DEFAULT_COOKIES: Map = mapOf() private val DEFAULT_REFERER: String? = null -fun Context.initRequestClient() { +fun Context.initRequestClient(): OkHttpClient { val settingsManager = PreferenceManager.getDefaultSharedPreferences(this) val dns = settingsManager.getInt(this.getString(R.string.dns_pref), 0) baseClient = OkHttpClient.Builder() @@ -44,6 +44,7 @@ fun Context.initRequestClient() { } // Needs to be build as otherwise the other builders will change this object .build() + return baseClient } /** WARNING! CAN ONLY BE READ ONCE */ diff --git a/app/src/main/java/com/lagradost/cloudstream3/network/WebViewResolver.kt b/app/src/main/java/com/lagradost/cloudstream3/network/WebViewResolver.kt index c92b70c0..ca695c0b 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/network/WebViewResolver.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/network/WebViewResolver.kt @@ -3,6 +3,7 @@ package com.lagradost.cloudstream3.network import android.annotation.SuppressLint import android.net.http.SslError import android.webkit.* +import androidx.core.view.contains import com.lagradost.cloudstream3.AcraApplication import com.lagradost.cloudstream3.utils.Coroutines.main import kotlinx.coroutines.delay @@ -10,6 +11,7 @@ import kotlinx.coroutines.runBlocking import okhttp3.Interceptor import okhttp3.Request import okhttp3.Response +import java.net.URI import java.util.concurrent.TimeUnit class WebViewResolver(val interceptUrl: Regex) : Interceptor { @@ -56,7 +58,7 @@ class WebViewResolver(val interceptUrl: Regex) : Interceptor { request: WebResourceRequest ): WebResourceResponse? { val webViewUrl = request.url.toString() -// println("Override url $webViewUrl") + if (interceptUrl.containsMatchIn(webViewUrl)) { fixedRequest = getRequestCreator( webViewUrl, @@ -71,7 +73,27 @@ class WebViewResolver(val interceptUrl: Regex) : Interceptor { println("Web-view request finished: $webViewUrl") 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?) { @@ -99,4 +121,18 @@ class WebViewResolver(val interceptUrl: Regex) : Interceptor { 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()) + } + } + } \ No newline at end of file diff --git a/app/src/main/java/com/lagradost/cloudstream3/utils/GlideApp.kt b/app/src/main/java/com/lagradost/cloudstream3/utils/GlideApp.kt index b9731742..400ca9fa 100644 --- a/app/src/main/java/com/lagradost/cloudstream3/utils/GlideApp.kt +++ b/app/src/main/java/com/lagradost/cloudstream3/utils/GlideApp.kt @@ -1,12 +1,18 @@ package com.lagradost.cloudstream3.utils import android.content.Context +import com.bumptech.glide.Glide import com.bumptech.glide.GlideBuilder +import com.bumptech.glide.Registry 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.model.GlideUrl import com.bumptech.glide.module.AppGlideModule import com.bumptech.glide.request.RequestOptions import com.bumptech.glide.signature.ObjectKey +import com.lagradost.cloudstream3.network.initRequestClient +import java.io.InputStream @GlideModule class GlideModule : AppGlideModule() { @@ -18,4 +24,16 @@ class GlideModule : AppGlideModule() { .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) + } } \ No newline at end of file