mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
optimized zoro and probably fixed sflix downloading
This commit is contained in:
parent
aab7e2dc6c
commit
c4d4173694
3 changed files with 88 additions and 93 deletions
|
@ -1,13 +1,15 @@
|
|||
package com.lagradost.cloudstream3.animeproviders
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.fasterxml.jackson.databind.util.NameTransformer
|
||||
import com.fasterxml.jackson.module.kotlin.readValue
|
||||
import com.lagradost.cloudstream3.*
|
||||
import com.lagradost.cloudstream3.APIHolder.getCaptchaToken
|
||||
import com.lagradost.cloudstream3.movieproviders.SflixProvider
|
||||
import com.lagradost.cloudstream3.movieproviders.SflixProvider.Companion.extractRabbitStream
|
||||
import com.lagradost.cloudstream3.movieproviders.SflixProvider.Companion.toExtractorLink
|
||||
import com.lagradost.cloudstream3.movieproviders.SflixProvider.Companion.toSubtitleFile
|
||||
import com.lagradost.cloudstream3.network.WebViewResolver
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import org.jsoup.Jsoup
|
||||
|
@ -328,42 +330,11 @@ class ZoroProvider : MainAPI() {
|
|||
val extractorLink = app.get(
|
||||
link,
|
||||
).mapped<RapidCloudResponse>().link
|
||||
//.also { println("AAAAAAAAA: ${it.text}") }
|
||||
// Loads the links in the appropriate extractor.
|
||||
val hasLoadedExtractorLink = loadExtractor(extractorLink, mainUrl, callback)
|
||||
|
||||
if (!hasLoadedExtractorLink) {
|
||||
|
||||
// Not an extractor because:
|
||||
// 1. No subtitle callback
|
||||
// 2. Missing dub/sub status in parameter (might be substituted in the referer)
|
||||
|
||||
val response =
|
||||
getM3u8FromRapidCloud(
|
||||
extractorLink
|
||||
)
|
||||
|
||||
if (response.contains("<html")) return@apmap
|
||||
val mapped = parseJson<SflixProvider.SourceObject>(response)
|
||||
|
||||
mapped.tracks?.forEach { track ->
|
||||
track?.toSubtitleFile()?.let { subtitleFile ->
|
||||
subtitleCallback.invoke(subtitleFile)
|
||||
}
|
||||
}
|
||||
|
||||
val list = listOf(
|
||||
mapped.sources to "source 1",
|
||||
mapped.sources1 to "source 2",
|
||||
mapped.sources2 to "source 3",
|
||||
mapped.sourcesBackup to "source backup"
|
||||
)
|
||||
|
||||
list.forEach { subList ->
|
||||
subList.first?.forEach { a ->
|
||||
a?.toExtractorLink(this, subList.second + " - ${it.first}", null)
|
||||
?.forEach(callback)
|
||||
}
|
||||
extractRabbitStream(extractorLink, subtitleCallback, callback) { sourceName ->
|
||||
sourceName + " - ${it.first}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -327,62 +327,11 @@ class SflixProvider(providerUrl: String, providerName: String) : MainAPI() {
|
|||
app.get("https://sflix.to/ajax/get_link/$serverId").mapped<IframeJson>().link
|
||||
?: return@suspendSafeApiCall
|
||||
|
||||
// ------- Iframe -------
|
||||
val mainIframeUrl =
|
||||
iframeLink.substringBeforeLast("/") // "https://rabbitstream.net/embed-4/6sBcv1i8vUF6?z=" -> "https://rabbitstream.net/embed-4"
|
||||
val mainIframeId = iframeLink.substringAfterLast("/")
|
||||
.substringBefore("?") // "https://rabbitstream.net/embed-4/6sBcv1i8vUF6?z=" -> "6sBcv1i8vUF6"
|
||||
|
||||
val iframe = app.get(iframeLink, referer = mainUrl)
|
||||
val iframeKey =
|
||||
iframe.document.select("script[src*=https://www.google.com/recaptcha/api.js?render=]")
|
||||
.attr("src").substringAfter("render=")
|
||||
val iframeToken = getCaptchaToken(iframeLink, iframeKey)
|
||||
val number = Regex("""recaptchaNumber = '(.*?)'""").find(iframe.text)?.groupValues?.get(1)
|
||||
|
||||
val mapped = app.get(
|
||||
"${mainIframeUrl.replace("/embed", "/ajax/embed")}/getSources?id=$mainIframeId&_token=$iframeToken&_number=$number",
|
||||
referer = "https://rabbitstream.net/",
|
||||
headers = mapOf(
|
||||
"X-Requested-With" to "XMLHttpRequest",
|
||||
"Accept" to "*/*",
|
||||
"Accept-Language" to "en-US,en;q=0.5",
|
||||
// "Cache-Control" to "no-cache",
|
||||
"Connection" to "keep-alive",
|
||||
// "Sec-Fetch-Dest" to "empty",
|
||||
// "Sec-Fetch-Mode" to "no-cors",
|
||||
// "Sec-Fetch-Site" to "cross-site",
|
||||
// "Pragma" to "no-cache",
|
||||
// "Cache-Control" to "no-cache",
|
||||
"TE" to "trailers"
|
||||
)
|
||||
).mapped<SourceObject>()
|
||||
|
||||
// Some smarter ws11 or w10 selection might be required in the future.
|
||||
val extractorData =
|
||||
"https://ws11.rabbitstream.net/socket.io/?EIO=4&transport=polling"
|
||||
|
||||
// val sources = resolved.first?.let { app.baseClient.newCall(it).execute().text }
|
||||
// ?: return@suspendSafeApiCall
|
||||
|
||||
// val mapped = parseJson<SourceObject>(sources)
|
||||
|
||||
mapped.tracks?.forEach {
|
||||
it?.toSubtitleFile()?.let { subtitleFile ->
|
||||
subtitleCallback.invoke(subtitleFile)
|
||||
}
|
||||
}
|
||||
|
||||
listOf(
|
||||
mapped.sources to "",
|
||||
mapped.sources1 to "source 2",
|
||||
mapped.sources2 to "source 3",
|
||||
mapped.sourcesBackup to "source backup"
|
||||
).forEach { (sources, sourceName) ->
|
||||
sources?.forEach {
|
||||
it?.toExtractorLink(this, sourceName, extractorData)?.forEach(callback)
|
||||
}
|
||||
}
|
||||
extractRabbitStream(iframeLink, subtitleCallback, callback, extractorData) { it }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -510,7 +459,7 @@ class SflixProvider(providerUrl: String, providerName: String) : MainAPI() {
|
|||
}
|
||||
|
||||
//.also { println("Sflix post job ${it.text}") }
|
||||
Log.d(this.name, "Running Sflix job $url")
|
||||
Log.d(this.name, "Running ${this.name} job $url")
|
||||
|
||||
val time = measureTimeMillis {
|
||||
// This acts as a timeout
|
||||
|
@ -620,6 +569,72 @@ class SflixProvider(providerUrl: String, providerName: String) : MainAPI() {
|
|||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
suspend fun MainAPI.extractRabbitStream(
|
||||
url: String,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit,
|
||||
/** Used for extractorLink name, input: Source name */
|
||||
extractorData: String? = null,
|
||||
nameTransformer: (String) -> String
|
||||
) {
|
||||
// https://rapid-cloud.ru/embed-6/dcPOVRE57YOT?z= -> https://rapid-cloud.ru/embed-6
|
||||
val mainIframeUrl =
|
||||
url.substringBeforeLast("/")
|
||||
val mainIframeId = url.substringAfterLast("/")
|
||||
.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)
|
||||
|
||||
val mapped = app.get(
|
||||
"${
|
||||
mainIframeUrl.replace(
|
||||
"/embed",
|
||||
"/ajax/embed"
|
||||
)
|
||||
}/getSources?id=$mainIframeId&_token=$iframeToken&_number=$number",
|
||||
referer = mainUrl,
|
||||
headers = mapOf(
|
||||
"X-Requested-With" to "XMLHttpRequest",
|
||||
"Accept" to "*/*",
|
||||
"Accept-Language" to "en-US,en;q=0.5",
|
||||
// "Cache-Control" to "no-cache",
|
||||
"Connection" to "keep-alive",
|
||||
// "Sec-Fetch-Dest" to "empty",
|
||||
// "Sec-Fetch-Mode" to "no-cors",
|
||||
// "Sec-Fetch-Site" to "cross-site",
|
||||
// "Pragma" to "no-cache",
|
||||
// "Cache-Control" to "no-cache",
|
||||
"TE" to "trailers"
|
||||
)
|
||||
).mapped<SourceObject>()
|
||||
|
||||
mapped.tracks?.forEach { track ->
|
||||
track?.toSubtitleFile()?.let { subtitleFile ->
|
||||
subtitleCallback.invoke(subtitleFile)
|
||||
}
|
||||
}
|
||||
|
||||
val list = listOf(
|
||||
mapped.sources to "source 1",
|
||||
mapped.sources1 to "source 2",
|
||||
mapped.sources2 to "source 3",
|
||||
mapped.sourcesBackup to "source backup"
|
||||
)
|
||||
|
||||
list.forEach { subList ->
|
||||
subList.first?.forEach { source ->
|
||||
source?.toExtractorLink(this, nameTransformer(subList.second), extractorData)
|
||||
?.forEach(callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import androidx.work.OneTimeWorkRequest
|
|||
import androidx.work.WorkManager
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.hippo.unifile.UniFile
|
||||
import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
|
||||
import com.lagradost.cloudstream3.AcraApplication.Companion.removeKey
|
||||
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
||||
import com.lagradost.cloudstream3.MainActivity
|
||||
|
@ -29,11 +30,13 @@ import com.lagradost.cloudstream3.R
|
|||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.mvvm.normalSafeApiCall
|
||||
import com.lagradost.cloudstream3.services.VideoDownloadService
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.ioSafe
|
||||
import com.lagradost.cloudstream3.utils.Coroutines.main
|
||||
import com.lagradost.cloudstream3.utils.DataStore.getKey
|
||||
import com.lagradost.cloudstream3.utils.DataStore.removeKey
|
||||
import com.lagradost.cloudstream3.utils.UIHelper.colorFromAttribute
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.Job
|
||||
import kotlinx.coroutines.delay
|
||||
import kotlinx.coroutines.withContext
|
||||
import okhttp3.internal.closeQuietly
|
||||
|
@ -677,7 +680,7 @@ object VideoDownloadManager {
|
|||
extension: String,
|
||||
tryResume: Boolean,
|
||||
parentId: Int?,
|
||||
createNotificationCallback: (CreateNotificationMetadata) -> Unit
|
||||
createNotificationCallback: (CreateNotificationMetadata) -> Unit,
|
||||
): Int {
|
||||
if (link.url.startsWith("magnet") || link.url.endsWith(".torrent")) {
|
||||
return ERROR_UNKNOWN
|
||||
|
@ -1135,7 +1138,6 @@ object VideoDownloadManager {
|
|||
|
||||
val displayName = getDisplayName(name, extension)
|
||||
|
||||
|
||||
val fileStream = stream.fileStream!!
|
||||
|
||||
val firstTs = tsIterator.next()
|
||||
|
@ -1346,6 +1348,13 @@ object VideoDownloadManager {
|
|||
val name =
|
||||
sanitizeFilename(ep.name ?: "${context.getString(R.string.episode)} ${ep.episode}")
|
||||
|
||||
// Make sure this is cancelled when download is done or cancelled.
|
||||
val extractorJob = ioSafe {
|
||||
if (link.extractorData != null) {
|
||||
getApiFromNameNull(link.source)?.extractorVerifierJob(link.extractorData)
|
||||
}
|
||||
}
|
||||
|
||||
if (link.isM3u8 || URI(link.url).path.endsWith(".m3u8")) {
|
||||
val startIndex = if (tryResume) {
|
||||
context.getKey<DownloadedFileInfo>(
|
||||
|
@ -1369,7 +1378,7 @@ object VideoDownloadManager {
|
|||
meta.hlsTotal
|
||||
)
|
||||
}
|
||||
}
|
||||
}.also { extractorJob.cancel() }
|
||||
}
|
||||
|
||||
return normalSafeApiCall {
|
||||
|
@ -1387,7 +1396,7 @@ object VideoDownloadManager {
|
|||
)
|
||||
}
|
||||
}
|
||||
} ?: ERROR_UNKNOWN
|
||||
}.also { extractorJob.cancel() } ?: ERROR_UNKNOWN
|
||||
}
|
||||
|
||||
fun downloadCheck(
|
||||
|
|
Loading…
Reference in a new issue