11package com.animesail
22
33import android.annotation.SuppressLint
4+ import android.net.http.SslError
45import android.os.Handler
56import android.os.Looper
67import android.webkit.CookieManager
8+ import android.webkit.SslErrorHandler
9+ import android.webkit.WebChromeClient
710import android.webkit.WebView
811import android.webkit.WebViewClient
912import com.fasterxml.jackson.annotation.JsonIgnoreProperties
@@ -22,9 +25,8 @@ import com.lagradost.cloudstream3.utils.Qualities
2225import com.lagradost.cloudstream3.utils.loadExtractor
2326import com.lagradost.cloudstream3.utils.newExtractorLink
2427import com.lagradost.nicehttp.NiceResponse
28+ import com.lagradost.nicehttp.Session
2529import kotlinx.coroutines.runBlocking
26- import kotlinx.coroutines.Dispatchers
27- import kotlinx.coroutines.delay
2830import okhttp3.Interceptor
2931import okhttp3.Response
3032import org.json.JSONObject
@@ -36,73 +38,138 @@ class TurnstileInterceptor(private val targetCookie: String = "_as_turnstile") :
3638 override fun intercept (chain : Interceptor .Chain ): Response {
3739 val originalRequest = chain.request()
3840 val url = originalRequest.url.toString()
41+ val domainUrl = " ${originalRequest.url.scheme} ://${originalRequest.url.host} "
42+
3943 val cookieManager = CookieManager .getInstance()
44+ cookieManager.setAcceptCookie(true )
4045
41- var currentCookies = cookieManager.getCookie(url) ? : " "
42- var userAgent = originalRequest.header(" User-Agent" ) ? : " "
46+ val standardUserAgent = " Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Mobile Safari/537.36"
4347
44- var response : Response ? = null
48+ var currentCookies = cookieManager.getCookie(domainUrl) ? : " "
4549 var needsRefresh = false
50+ var initialResponse: Response ? = null
4651
47- if (! currentCookies.contains(targetCookie)) {
48- needsRefresh = true
49- } else {
52+ if (currentCookies.contains(targetCookie) || currentCookies.contains(" _as_turnstile" )) {
5053 val requestBuilder = originalRequest.newBuilder()
51- .header(" Cookie" , currentCookies)
52- response = chain.proceed(requestBuilder.build())
54+ .removeHeader(" User-Agent" )
55+ .addHeader(" User-Agent" , standardUserAgent)
56+ .removeHeader(" Cookie" )
57+ .addHeader(" Cookie" , currentCookies)
5358
54- if (response.code == 403 || response.code == 503 ) {
59+ initialResponse = chain.proceed(requestBuilder.build())
60+
61+ if (initialResponse.code in listOf (403 , 503 , 202 )) {
5562 needsRefresh = true
56- response.close()
63+ initialResponse.close()
64+ } else {
65+ return initialResponse
5766 }
67+ } else {
68+ needsRefresh = true
5869 }
5970
6071 if (needsRefresh) {
61- runBlocking(Dispatchers .Main ) {
62- val context = AcraApplication .context
63- if (context != null ) {
64- val webView = WebView (context)
65-
66- webView.settings.javaScriptEnabled = true
67- webView.settings.domStorageEnabled = true
68- webView.settings.userAgentString = userAgent.ifBlank { webView.settings.userAgentString }
69- userAgent = webView.settings.userAgentString
70-
71- webView.webViewClient = object : WebViewClient () {
72- override fun onPageFinished (view : WebView ? , url : String? ) {
73- super .onPageFinished(view, url)
72+ val context = AcraApplication .context
73+ if (context != null ) {
74+ val handler = Handler (Looper .getMainLooper())
75+ var webView: WebView ? = null
76+ var isResolved = false
77+
78+ handler.post {
79+ try {
80+ val newWebView = WebView (context)
81+ webView = newWebView
82+
83+ newWebView.resumeTimers()
84+ newWebView.onResume()
85+ newWebView.layoutParams = android.view.ViewGroup .LayoutParams (1080 , 1920 )
86+
87+ cookieManager.setAcceptThirdPartyCookies(newWebView, true )
88+
89+ newWebView.settings.apply {
90+ javaScriptEnabled = true
91+ domStorageEnabled = true
92+ databaseEnabled = true
93+ useWideViewPort = true
94+ loadWithOverviewMode = true
95+ mixedContentMode = android.webkit.WebSettings .MIXED_CONTENT_ALWAYS_ALLOW
96+ cacheMode = android.webkit.WebSettings .LOAD_NO_CACHE
97+ userAgentString = standardUserAgent
98+ mediaPlaybackRequiresUserGesture = false
99+ javaScriptCanOpenWindowsAutomatically = true
74100 }
75- }
76-
77- cookieManager.setCookie(url, " $targetCookie =; Max-Age=0" )
101+
102+ newWebView.clearCache(true )
103+ newWebView.clearHistory()
104+
105+ newWebView.webChromeClient = WebChromeClient ()
106+ newWebView.webViewClient = object : WebViewClient () {
107+ @SuppressLint(" WebViewClientOnReceivedSslError" )
108+ override fun onReceivedSslError (view : WebView ? , handler : SslErrorHandler ? , error : SslError ? ) {
109+ handler?.proceed()
110+ }
78111
79- webView.loadUrl(url)
112+ override fun onPageFinished (view : WebView ? , url : String? ) {
113+ super .onPageFinished(view, url)
114+ val checkCookies = cookieManager.getCookie(domainUrl) ? : " "
115+ if (checkCookies.contains(targetCookie) || checkCookies.contains(" _as_turnstile" )) {
116+ isResolved = true
117+ }
118+ }
119+ }
80120
81- var attempts = 0
82- val maxAttempts = 60
83- while (attempts < maxAttempts) {
84- delay(1000 )
85- val checkCookies = cookieManager.getCookie(url) ? : " "
86- if (checkCookies.contains(targetCookie)) {
87- break
121+ val challengeCookies = listOf (targetCookie, " _as_turnstile" )
122+ challengeCookies.forEach { cookie ->
123+ cookieManager.setCookie(domainUrl, " $cookie =; Max-Age=0" )
88124 }
89- attempts++
125+ cookieManager.flush()
126+
127+ newWebView.loadUrl(url)
128+ } catch (e: Exception ) {
129+ e.printStackTrace()
90130 }
131+ }
132+
133+ var attempts = 0
134+ val maxAttempts = 60
135+ while (attempts < maxAttempts) {
136+ Thread .sleep(1000 )
137+ val checkCookies = cookieManager.getCookie(domainUrl) ? : " "
138+
139+ if (checkCookies.contains(targetCookie) || checkCookies.contains(" _as_turnstile" ) || isResolved) {
140+ cookieManager.flush()
141+ break
142+ }
143+ attempts++
144+ }
91145
92- webView.stopLoading()
93- webView.destroy()
146+ handler.post {
147+ try {
148+ webView?.stopLoading()
149+ webView?.destroy()
150+ } catch (e: Exception ) {
151+ e.printStackTrace()
152+ }
94153 }
95154 }
96155
97- currentCookies = cookieManager.getCookie(url) ? : " "
98- val newRequestBuilder = originalRequest.newBuilder()
99- .header(" User-Agent" , userAgent)
100- .header(" Cookie" , currentCookies)
156+ currentCookies = cookieManager.getCookie(domainUrl) ? : " "
101157
102- response = chain.proceed(newRequestBuilder.build())
158+ val newRequestBuilder = originalRequest.newBuilder()
159+ .removeHeader(" User-Agent" )
160+ .addHeader(" User-Agent" , standardUserAgent)
161+ .removeHeader(" Cookie" )
162+ .addHeader(" Cookie" , currentCookies)
163+
164+ return chain.proceed(newRequestBuilder.build())
103165 }
104166
105- return response ? : chain.proceed(originalRequest)
167+ val finalRequest = originalRequest.newBuilder()
168+ .removeHeader(" User-Agent" )
169+ .addHeader(" User-Agent" , standardUserAgent)
170+ .build()
171+
172+ return initialResponse ? : chain.proceed(finalRequest)
106173 }
107174}
108175
@@ -113,6 +180,10 @@ class AnimeSailProvider : MainAPI() {
113180 override var lang = " id"
114181 override val hasDownloadSupport = true
115182
183+ private val fetch by lazy {
184+ Session (app.baseClient.newBuilder().addInterceptor(TurnstileInterceptor ()).build())
185+ }
186+
116187 override val supportedTypes = setOf (
117188 TvType .Anime ,
118189 TvType .AnimeMovie ,
@@ -140,12 +211,10 @@ class AnimeSailProvider : MainAPI() {
140211 }
141212
142213 private suspend fun request (url : String , ref : String? = null): NiceResponse {
143- return app .get(
214+ return fetch .get(
144215 url,
145- interceptor = TurnstileInterceptor (" _as_turnstile" ),
146216 headers = mapOf (
147217 " Accept" to " text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8" ,
148- " User-Agent" to " Mozilla/5.0 (Linux; Android 10; K) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/121.0.0.0 Mobile Safari/537.36" ,
149218 ),
150219 referer = ref
151220 )
0 commit comments