mirror of
https://github.com/recloudstream/cloudstream-extensions.git
synced 2024-08-15 03:03:54 +00:00
Sflix fix
This commit is contained in:
parent
865fcf8dc1
commit
f61cdc0cf7
3 changed files with 237 additions and 141 deletions
|
@ -1,5 +1,5 @@
|
||||||
// use an integer for version numbers
|
// use an integer for version numbers
|
||||||
version = 8
|
version = 9
|
||||||
|
|
||||||
|
|
||||||
cloudstream {
|
cloudstream {
|
||||||
|
|
|
@ -3,22 +3,23 @@ package com.lagradost
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
import com.lagradost.cloudstream3.*
|
import com.lagradost.cloudstream3.*
|
||||||
|
import com.lagradost.cloudstream3.APIHolder.getCaptchaToken
|
||||||
import com.lagradost.cloudstream3.APIHolder.unixTimeMS
|
import com.lagradost.cloudstream3.APIHolder.unixTimeMS
|
||||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
|
import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
|
||||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addDuration
|
import com.lagradost.cloudstream3.LoadResponse.Companion.addDuration
|
||||||
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
|
||||||
import com.lagradost.cloudstream3.mvvm.Resource
|
//import com.lagradost.cloudstream3.animeproviders.ZoroProvider
|
||||||
import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall
|
import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall
|
||||||
|
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
||||||
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
||||||
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||||
import com.lagradost.cloudstream3.utils.M3u8Helper
|
import com.lagradost.cloudstream3.utils.M3u8Helper
|
||||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||||
import com.lagradost.nicehttp.requestCreator
|
import com.lagradost.nicehttp.NiceResponse
|
||||||
import kotlinx.coroutines.delay
|
import kotlinx.coroutines.delay
|
||||||
import okhttp3.WebSocket
|
import okhttp3.RequestBody.Companion.toRequestBody
|
||||||
import okhttp3.WebSocketListener
|
|
||||||
import org.jsoup.Jsoup
|
import org.jsoup.Jsoup
|
||||||
import org.jsoup.nodes.Element
|
import org.jsoup.nodes.Element
|
||||||
import java.net.URI
|
import java.net.URI
|
||||||
|
@ -28,6 +29,7 @@ import java.util.*
|
||||||
import javax.crypto.Cipher
|
import javax.crypto.Cipher
|
||||||
import javax.crypto.spec.IvParameterSpec
|
import javax.crypto.spec.IvParameterSpec
|
||||||
import javax.crypto.spec.SecretKeySpec
|
import javax.crypto.spec.SecretKeySpec
|
||||||
|
import kotlin.system.measureTimeMillis
|
||||||
|
|
||||||
open class SflixProvider : MainAPI() {
|
open class SflixProvider : MainAPI() {
|
||||||
override var mainUrl = "https://sflix.to"
|
override var mainUrl = "https://sflix.to"
|
||||||
|
@ -356,12 +358,13 @@ open class SflixProvider : MainAPI() {
|
||||||
// val extractorData =
|
// val extractorData =
|
||||||
// "https://ws11.rabbitstream.net/socket.io/?EIO=4&transport=polling"
|
// "https://ws11.rabbitstream.net/socket.io/?EIO=4&transport=polling"
|
||||||
|
|
||||||
val hasLoadedExtractor = loadExtractor(iframeLink, null, subtitleCallback, callback)
|
if (!loadExtractor(iframeLink, null, subtitleCallback, callback)) {
|
||||||
if (!hasLoadedExtractor) {
|
|
||||||
extractRabbitStream(
|
extractRabbitStream(
|
||||||
iframeLink,
|
iframeLink,
|
||||||
subtitleCallback,
|
subtitleCallback,
|
||||||
callback,
|
callback,
|
||||||
|
false,
|
||||||
|
decryptKey = getKey()
|
||||||
) { it }
|
) { it }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -370,6 +373,10 @@ open class SflixProvider : MainAPI() {
|
||||||
return !urls.isNullOrEmpty()
|
return !urls.isNullOrEmpty()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// override suspend fun extractorVerifierJob(extractorData: String?) {
|
||||||
|
// runSflixExtractorVerifierJob(this, extractorData, "https://rabbitstream.net/")
|
||||||
|
// }
|
||||||
|
|
||||||
private fun Element.toSearchResult(): SearchResponse {
|
private fun Element.toSearchResult(): SearchResponse {
|
||||||
val inner = this.selectFirst("div.film-poster")
|
val inner = this.selectFirst("div.film-poster")
|
||||||
val img = inner!!.select("img")
|
val img = inner!!.select("img")
|
||||||
|
@ -450,69 +457,149 @@ open class SflixProvider : MainAPI() {
|
||||||
return code.reversed()
|
return code.reversed()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getSourceObject(responseJson: String?, decryptKey: String?): SourceObject? {
|
suspend fun getKey(): String? {
|
||||||
if (responseJson == null) return null
|
data class KeyObject(
|
||||||
return if (decryptKey != null) {
|
@JsonProperty("key") val key: String? = null
|
||||||
val encryptedMap = tryParseJson<SourceObjectEncrypted>(responseJson)
|
)
|
||||||
val sources = encryptedMap?.sources
|
return app.get("https://raw.githubusercontent.com/BlipBlob/blabflow/main/keys.json")
|
||||||
|
.parsed<KeyObject>().key
|
||||||
if (sources == null || encryptedMap.encrypted == false) {
|
|
||||||
tryParseJson(responseJson)
|
|
||||||
} else {
|
|
||||||
val decrypted = decryptMapped<List<Sources>>(sources, decryptKey)
|
|
||||||
SourceObject(
|
|
||||||
sources = decrypted,
|
|
||||||
tracks = encryptedMap.tracks
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
tryParseJson(responseJson)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getSources(
|
/**
|
||||||
socketUrl: String,
|
* Generates a session
|
||||||
id: String,
|
* 1 Get request.
|
||||||
callback: suspend (Resource<SourceObject>) -> Unit
|
* */
|
||||||
) {
|
private suspend fun negotiateNewSid(baseUrl: String): PollingData? {
|
||||||
app.baseClient.newWebSocket(
|
// Tries multiple times
|
||||||
requestCreator("GET", socketUrl),
|
for (i in 1..5) {
|
||||||
object : WebSocketListener() {
|
val jsonText =
|
||||||
val sidRegex = Regex("""sid.*"(.*?)"""")
|
app.get("$baseUrl&t=${generateTimeStamp()}").text.replaceBefore("{", "")
|
||||||
val sourceRegex = Regex("""\{.*\}""")
|
// println("Negotiated sid $jsonText")
|
||||||
val codeRegex = Regex("""^\d*""")
|
parseJson<PollingData?>(jsonText)?.let { return it }
|
||||||
|
delay(1000L * i)
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
var key: String? = null
|
/**
|
||||||
|
* Generates a new session if the request fails
|
||||||
|
* @return the data and if it is new.
|
||||||
|
* */
|
||||||
|
private suspend fun getUpdatedData(
|
||||||
|
response: NiceResponse,
|
||||||
|
data: PollingData,
|
||||||
|
baseUrl: String
|
||||||
|
): Pair<PollingData, Boolean> {
|
||||||
|
if (!response.okhttpResponse.isSuccessful) {
|
||||||
|
return negotiateNewSid(baseUrl)?.let {
|
||||||
|
it to true
|
||||||
|
} ?: (data to false)
|
||||||
|
}
|
||||||
|
return data to false
|
||||||
|
}
|
||||||
|
|
||||||
override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
|
|
||||||
ioSafe {
|
|
||||||
callback(Resource.Failure(false, code, null, reason))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onMessage(webSocket: WebSocket, text: String) {
|
private suspend fun initPolling(
|
||||||
Log.d("getSources", "onMessage $text")
|
extractorData: String,
|
||||||
val code = codeRegex.find(text)?.value?.toIntOrNull() ?: return
|
referer: String
|
||||||
|
): Pair<PollingData?, String?> {
|
||||||
when (code) {
|
val headers = mapOf(
|
||||||
0 -> webSocket.send("40")
|
"Referer" to referer // "https://rabbitstream.net/"
|
||||||
40 -> {
|
|
||||||
key = sidRegex.find(text)?.groupValues?.get(1)
|
|
||||||
webSocket.send("""42["getSources",{"id":"$id"}]""")
|
|
||||||
}
|
|
||||||
42 -> {
|
|
||||||
val response = sourceRegex.find(text)?.value
|
|
||||||
val sourceObject = getSourceObject(response, key)
|
|
||||||
val resource = if (sourceObject == null)
|
|
||||||
Resource.Failure(false, null, null, response ?: "")
|
|
||||||
else Resource.Success(sourceObject)
|
|
||||||
ioSafe { callback(resource) }
|
|
||||||
webSocket.close(1005, "41")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val data = negotiateNewSid(extractorData) ?: return null to null
|
||||||
|
app.post(
|
||||||
|
"$extractorData&t=${generateTimeStamp()}&sid=${data.sid}",
|
||||||
|
requestBody = "40".toRequestBody(),
|
||||||
|
headers = headers
|
||||||
|
)
|
||||||
|
|
||||||
|
// This makes the second get request work, and re-connect work.
|
||||||
|
val reconnectSid =
|
||||||
|
parseJson<PollingData>(
|
||||||
|
app.get(
|
||||||
|
"$extractorData&t=${generateTimeStamp()}&sid=${data.sid}",
|
||||||
|
headers = headers
|
||||||
|
)
|
||||||
|
// .also { println("First get ${it.text}") }
|
||||||
|
.text.replaceBefore("{", "")
|
||||||
|
).sid
|
||||||
|
|
||||||
|
// This response is used in the post requests. Same contents in all it seems.
|
||||||
|
val authInt =
|
||||||
|
app.get(
|
||||||
|
"$extractorData&t=${generateTimeStamp()}&sid=${data.sid}",
|
||||||
|
timeout = 60,
|
||||||
|
headers = headers
|
||||||
|
).text
|
||||||
|
//.also { println("Second get ${it}") }
|
||||||
|
// Dunno if it's actually generated like this, just guessing.
|
||||||
|
.toIntOrNull()?.plus(1) ?: 3
|
||||||
|
|
||||||
|
return data to reconnectSid
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun runSflixExtractorVerifierJob(
|
||||||
|
api: MainAPI,
|
||||||
|
extractorData: String?,
|
||||||
|
referer: String
|
||||||
|
) {
|
||||||
|
if (extractorData == null) return
|
||||||
|
val headers = mapOf(
|
||||||
|
"Referer" to referer // "https://rabbitstream.net/"
|
||||||
|
)
|
||||||
|
|
||||||
|
lateinit var data: PollingData
|
||||||
|
var reconnectSid = ""
|
||||||
|
|
||||||
|
initPolling(extractorData, referer)
|
||||||
|
.also {
|
||||||
|
data = it.first ?: throw RuntimeException("Data Null")
|
||||||
|
reconnectSid = it.second ?: throw RuntimeException("ReconnectSid Null")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Prevents them from fucking us over with doing a while(true){} loop
|
||||||
|
val interval = maxOf(data.pingInterval?.toLong()?.plus(2000) ?: return, 10000L)
|
||||||
|
var reconnect = false
|
||||||
|
var newAuth = false
|
||||||
|
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
val authData =
|
||||||
|
when {
|
||||||
|
newAuth -> "40"
|
||||||
|
reconnect -> """42["_reconnect", "$reconnectSid"]"""
|
||||||
|
else -> "3"
|
||||||
|
}
|
||||||
|
|
||||||
|
val url = "${extractorData}&t=${generateTimeStamp()}&sid=${data.sid}"
|
||||||
|
|
||||||
|
getUpdatedData(
|
||||||
|
app.post(url, json = authData, headers = headers),
|
||||||
|
data,
|
||||||
|
extractorData
|
||||||
|
).also {
|
||||||
|
newAuth = it.second
|
||||||
|
data = it.first
|
||||||
|
}
|
||||||
|
|
||||||
|
//.also { println("Sflix post job ${it.text}") }
|
||||||
|
Log.d(api.name, "Running ${api.name} job $url")
|
||||||
|
|
||||||
|
val time = measureTimeMillis {
|
||||||
|
// This acts as a timeout
|
||||||
|
val getResponse = app.get(
|
||||||
|
url,
|
||||||
|
timeout = interval / 1000,
|
||||||
|
headers = headers
|
||||||
|
)
|
||||||
|
// .also { println("Sflix get job ${it.text}") }
|
||||||
|
reconnect = getResponse.text.contains("sid")
|
||||||
|
}
|
||||||
|
// Always waits even if the get response is instant, to prevent a while true loop.
|
||||||
|
if (time < interval - 4000)
|
||||||
|
delay(4000)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only scrape servers with these names
|
// Only scrape servers with these names
|
||||||
|
@ -522,8 +609,7 @@ open class SflixProvider : MainAPI() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// For re-use in Zoro
|
// For re-use in Zoro
|
||||||
private suspend
|
private suspend fun Sources.toExtractorLink(
|
||||||
fun Sources.toExtractorLink(
|
|
||||||
caller: MainAPI,
|
caller: MainAPI,
|
||||||
name: String,
|
name: String,
|
||||||
extractorData: String? = null,
|
extractorData: String? = null,
|
||||||
|
@ -605,10 +691,7 @@ open class SflixProvider : MainAPI() {
|
||||||
return currentKey
|
return currentKey
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun decryptSourceUrl(
|
private fun decryptSourceUrl(decryptionKey: ByteArray, sourceUrl: String): String {
|
||||||
decryptionKey: ByteArray,
|
|
||||||
sourceUrl: String
|
|
||||||
): String {
|
|
||||||
val cipherData = base64DecodeArray(sourceUrl)
|
val cipherData = base64DecodeArray(sourceUrl)
|
||||||
val encrypted = cipherData.copyOfRange(16, cipherData.size)
|
val encrypted = cipherData.copyOfRange(16, cipherData.size)
|
||||||
val aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding")
|
val aesCBC = Cipher.getInstance("AES/CBC/PKCS5Padding")
|
||||||
|
@ -624,8 +707,7 @@ open class SflixProvider : MainAPI() {
|
||||||
return String(decryptedData, StandardCharsets.UTF_8)
|
return String(decryptedData, StandardCharsets.UTF_8)
|
||||||
}
|
}
|
||||||
|
|
||||||
private inline
|
private inline fun <reified T> decryptMapped(input: String, key: String): T? {
|
||||||
fun <reified T> decryptMapped(input: String, key: String): T? {
|
|
||||||
return tryParseJson(decrypt(input, key))
|
return tryParseJson(decrypt(input, key))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -642,89 +724,103 @@ open class SflixProvider : MainAPI() {
|
||||||
url: String,
|
url: String,
|
||||||
subtitleCallback: (SubtitleFile) -> Unit,
|
subtitleCallback: (SubtitleFile) -> Unit,
|
||||||
callback: (ExtractorLink) -> Unit,
|
callback: (ExtractorLink) -> Unit,
|
||||||
|
useSidAuthentication: Boolean,
|
||||||
|
/** Used for extractorLink name, input: Source name */
|
||||||
|
extractorData: String? = null,
|
||||||
|
decryptKey: String? = null,
|
||||||
nameTransformer: (String) -> String,
|
nameTransformer: (String) -> String,
|
||||||
) = suspendSafeApiCall {
|
) = suspendSafeApiCall {
|
||||||
// https://rapid-cloud.ru/embed-6/dcPOVRE57YOT?z= -> https://rapid-cloud.ru/embed-6
|
// https://rapid-cloud.ru/embed-6/dcPOVRE57YOT?z= -> https://rapid-cloud.ru/embed-6
|
||||||
// val mainIframeUrl =
|
val mainIframeUrl =
|
||||||
// url.substringBeforeLast("/")
|
url.substringBeforeLast("/")
|
||||||
|
|
||||||
val mainIframeId = url.substringAfterLast("/")
|
val mainIframeId = url.substringAfterLast("/")
|
||||||
.substringBefore("?") // https://rapid-cloud.ru/embed-6/dcPOVRE57YOT?z= -> dcPOVRE57YOT
|
.substringBefore("?") // https://rapid-cloud.ru/embed-6/dcPOVRE57YOT?z= -> dcPOVRE57YOT
|
||||||
|
// val iframe = app.get(url, referer = mainUrl)
|
||||||
|
// val iframeKey =
|
||||||
|
// iframe.document.select("script[src*=https://www.google.com/recaptcha/api.js?render=]")
|
||||||
|
// .attr("src").substringAfter("render=")
|
||||||
|
// val iframeToken = getCaptchaToken(url, iframeKey)
|
||||||
|
// val number =
|
||||||
|
// Regex("""recaptchaNumber = '(.*?)'""").find(iframe.text)?.groupValues?.get(1)
|
||||||
|
|
||||||
var isDone = false
|
var sid: String? = null
|
||||||
|
if (useSidAuthentication && extractorData != null) {
|
||||||
|
negotiateNewSid(extractorData)?.also { pollingData ->
|
||||||
|
app.post(
|
||||||
|
"$extractorData&t=${generateTimeStamp()}&sid=${pollingData.sid}",
|
||||||
|
requestBody = "40".toRequestBody(),
|
||||||
|
timeout = 60
|
||||||
|
)
|
||||||
|
val text = app.get(
|
||||||
|
"$extractorData&t=${generateTimeStamp()}&sid=${pollingData.sid}",
|
||||||
|
timeout = 60
|
||||||
|
).text.replaceBefore("{", "")
|
||||||
|
|
||||||
// Hardcoded for now, does not support Zoro yet.
|
sid = parseJson<PollingData>(text).sid
|
||||||
getSources(
|
ioSafe { app.get("$extractorData&t=${generateTimeStamp()}&sid=${pollingData.sid}") }
|
||||||
"wss://wsx.dokicloud.one/socket.io/?EIO=4&transport=websocket",
|
|
||||||
mainIframeId
|
|
||||||
) { sourceResource ->
|
|
||||||
if (sourceResource !is Resource.Success) {
|
|
||||||
isDone = true
|
|
||||||
return@getSources
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
val sourceObject = sourceResource.value
|
val getSourcesUrl = "${
|
||||||
|
mainIframeUrl.replace(
|
||||||
sourceObject.tracks?.forEach { track ->
|
"/embed",
|
||||||
track?.toSubtitleFile()?.let { subtitleFile ->
|
"/ajax/embed"
|
||||||
subtitleCallback.invoke(subtitleFile)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
val list = listOf(
|
|
||||||
sourceObject.sources to "source 1",
|
|
||||||
sourceObject.sources1 to "source 2",
|
|
||||||
sourceObject.sources2 to "source 3",
|
|
||||||
sourceObject.sourcesBackup to "source backup"
|
|
||||||
)
|
)
|
||||||
|
}/getSources?id=$mainIframeId${sid?.let { "$&sId=$it" } ?: ""}"
|
||||||
|
val response = app.get(
|
||||||
|
getSourcesUrl,
|
||||||
|
referer = mainUrl,
|
||||||
|
headers = mapOf(
|
||||||
|
"X-Requested-With" to "XMLHttpRequest",
|
||||||
|
"Accept" to "*/*",
|
||||||
|
"Accept-Language" to "en-US,en;q=0.5",
|
||||||
|
"Connection" to "keep-alive",
|
||||||
|
"TE" to "trailers"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
list.forEach { subList ->
|
val sourceObject = if (decryptKey != null) {
|
||||||
subList.first?.forEach { source ->
|
val encryptedMap = response.parsedSafe<SourceObjectEncrypted>()
|
||||||
source?.toExtractorLink(
|
val sources = encryptedMap?.sources
|
||||||
this,
|
if (sources == null || encryptedMap.encrypted == false) {
|
||||||
nameTransformer(subList.second),
|
response.parsedSafe()
|
||||||
)?.forEach(callback)
|
} else {
|
||||||
}
|
val decrypted = decryptMapped<List<Sources>>(sources, decryptKey)
|
||||||
|
SourceObject(
|
||||||
|
sources = decrypted,
|
||||||
|
tracks = encryptedMap.tracks
|
||||||
|
)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
response.parsedSafe()
|
||||||
|
} ?: return@suspendSafeApiCall
|
||||||
|
|
||||||
|
sourceObject.tracks?.forEach { track ->
|
||||||
|
track?.toSubtitleFile()?.let { subtitleFile ->
|
||||||
|
subtitleCallback.invoke(subtitleFile)
|
||||||
}
|
}
|
||||||
isDone = true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var elapsedTime = 0
|
val list = listOf(
|
||||||
val maxTime = 30
|
sourceObject.sources to "source 1",
|
||||||
|
sourceObject.sources1 to "source 2",
|
||||||
|
sourceObject.sources2 to "source 3",
|
||||||
|
sourceObject.sourcesBackup to "source backup"
|
||||||
|
)
|
||||||
|
|
||||||
while (elapsedTime < maxTime && !isDone) {
|
list.forEach { subList ->
|
||||||
elapsedTime++
|
subList.first?.forEach { source ->
|
||||||
delay(1_000)
|
source?.toExtractorLink(
|
||||||
|
this,
|
||||||
|
nameTransformer(subList.second),
|
||||||
|
extractorData,
|
||||||
|
)
|
||||||
|
?.forEach {
|
||||||
|
// Sets Zoro SID used for video loading
|
||||||
|
// (this as? ZoroProvider)?.sid?.set(it.url.hashCode(), sid)
|
||||||
|
callback(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//// val iframe = app.get(url, referer = mainUrl)
|
|
||||||
//// val iframeKey =
|
|
||||||
//// iframe.document.select("script[src*=https://www.google.com/recaptcha/api.js?render=]")
|
|
||||||
//// .attr("src").substringAfter("render=")
|
|
||||||
//// val iframeToken = getCaptchaToken(url, iframeKey)
|
|
||||||
//// val number =
|
|
||||||
//// Regex("""recaptchaNumber = '(.*?)'""").find(iframe.text)?.groupValues?.get(1)
|
|
||||||
//
|
|
||||||
// val sid = null
|
|
||||||
// val getSourcesUrl = "${
|
|
||||||
// mainIframeUrl.replace(
|
|
||||||
// "/embed",
|
|
||||||
// "/ajax/embed"
|
|
||||||
// )
|
|
||||||
// }/getSources?id=$mainIframeId${sid?.let { "$&sId=$it" } ?: ""}"
|
|
||||||
// val response = app.get(
|
|
||||||
// getSourcesUrl,
|
|
||||||
// referer = mainUrl,
|
|
||||||
// headers = mapOf(
|
|
||||||
// "X-Requested-With" to "XMLHttpRequest",
|
|
||||||
// "Accept" to "*/*",
|
|
||||||
// "Accept-Language" to "en-US,en;q=0.5",
|
|
||||||
// "Connection" to "keep-alive",
|
|
||||||
// "TE" to "trailers"
|
|
||||||
// )
|
|
||||||
// )
|
|
||||||
//
|
|
||||||
// println("Sflix response: $response")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,7 @@ class TwoEmbedProvider : TmdbProvider() {
|
||||||
val mappedservers = parseJson<EmbedJson>(ajax)
|
val mappedservers = parseJson<EmbedJson>(ajax)
|
||||||
val iframeLink = mappedservers.link
|
val iframeLink = mappedservers.link
|
||||||
if (iframeLink.contains("rabbitstream")) {
|
if (iframeLink.contains("rabbitstream")) {
|
||||||
extractRabbitStream(iframeLink, subtitleCallback, callback) { it }
|
extractRabbitStream(iframeLink, subtitleCallback, callback, false, decryptKey = SflixProvider.getKey()) { it }
|
||||||
} else {
|
} else {
|
||||||
loadExtractor(iframeLink, embedUrl, subtitleCallback, callback)
|
loadExtractor(iframeLink, embedUrl, subtitleCallback, callback)
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue