forked from recloudstream/cloudstream
massively improved zoro
This commit is contained in:
parent
4b0a3e0c4e
commit
2a55a256aa
5 changed files with 105 additions and 53 deletions
|
@ -8,6 +8,7 @@ import com.lagradost.cloudstream3.movieproviders.SflixProvider.Companion.toExtra
|
|||
import com.lagradost.cloudstream3.movieproviders.SflixProvider.Companion.toSubtitleFile
|
||||
import com.lagradost.cloudstream3.network.WebViewResolver
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.nodes.Element
|
||||
import java.net.URI
|
||||
|
@ -152,7 +153,8 @@ class ZoroProvider : MainAPI() {
|
|||
EnumSet.of(DubStatus.Subbed)
|
||||
}
|
||||
|
||||
val tvType = getType(it.selectFirst(".film-detail > .fd-infor > .fdi-item")?.text().toString())
|
||||
val tvType =
|
||||
getType(it.selectFirst(".film-detail > .fd-infor > .fdi-item")?.text().toString())
|
||||
val href = fixUrl(it.selectFirst(".film-name a").attr("href"))
|
||||
|
||||
AnimeSearchResponse(
|
||||
|
@ -187,7 +189,8 @@ class ZoroProvider : MainAPI() {
|
|||
when {
|
||||
(year != null && japaneseTitle != null && status != null) -> break
|
||||
text.contains("Premiered") && year == null ->
|
||||
year = info.selectFirst(".name")?.text().toString().split(" ").last().toIntOrNull()
|
||||
year =
|
||||
info.selectFirst(".name")?.text().toString().split(" ").last().toIntOrNull()
|
||||
|
||||
text.contains("Japanese") && japaneseTitle == null ->
|
||||
japaneseTitle = info.selectFirst(".name")?.text().toString()
|
||||
|
@ -255,61 +258,59 @@ class ZoroProvider : MainAPI() {
|
|||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
|
||||
// Copy pasted from Sflix :)
|
||||
|
||||
val servers: List<Pair<DubStatus, String>> = Jsoup.parse(
|
||||
mapper.readValue<Response>(
|
||||
app.get("$mainUrl/ajax/v2/episode/servers?episodeId=" + data.split("=")[1]).text
|
||||
).html
|
||||
app.get("$mainUrl/ajax/v2/episode/servers?episodeId=" + data.split("=")[1])
|
||||
.mapped<Response>().html
|
||||
).select(".server-item[data-type][data-id]").map {
|
||||
Pair(if (it.attr("data-type") == "sub") DubStatus.Subbed else DubStatus.Dubbed, it.attr("data-id")!!)
|
||||
}
|
||||
|
||||
val res = app.get(
|
||||
data,
|
||||
interceptor = WebViewResolver(
|
||||
Regex("""/getSources""")
|
||||
)
|
||||
)
|
||||
// println("RES TEXT ${res.text}")
|
||||
|
||||
val recaptchaToken = res.response.request.url.queryParameter("_token")
|
||||
|
||||
val responses = servers.map {
|
||||
val link = "$mainUrl/ajax/v2/episode/sources?id=${it.second}&_token=$recaptchaToken"
|
||||
Pair(
|
||||
it.first,
|
||||
getM3u8FromRapidCloud(
|
||||
mapper.readValue<RapidCloudResponse>(
|
||||
app.get(
|
||||
link,
|
||||
res.headers.toMap()
|
||||
).text
|
||||
).link
|
||||
)
|
||||
if (it.attr("data-type") == "sub") DubStatus.Subbed else DubStatus.Dubbed,
|
||||
it.attr("data-id")!!
|
||||
)
|
||||
}
|
||||
|
||||
responses.forEach {
|
||||
if (it.second.contains("<html")) return@forEach
|
||||
val mapped = mapper.readValue<SflixProvider.SourceObject>(it.second)
|
||||
// Prevent duplicates
|
||||
servers.distinctBy { it.second }.pmap {
|
||||
val link =
|
||||
"$mainUrl/ajax/v2/episode/sources?id=${it.second}"
|
||||
val extractorLink = app.get(
|
||||
link,
|
||||
).mapped<RapidCloudResponse>().link
|
||||
|
||||
mapped.tracks?.forEach { track ->
|
||||
track?.toSubtitleFile()?.let { subtitleFile ->
|
||||
subtitleCallback.invoke(subtitleFile)
|
||||
// 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@pmap
|
||||
val mapped = mapper.readValue<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"
|
||||
)
|
||||
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}")?.forEach(callback)
|
||||
list.forEach { subList ->
|
||||
subList.first?.forEach { a ->
|
||||
a?.toExtractorLink(this, subList.second + " - ${it.first}")
|
||||
?.forEach(callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,45 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.network.WebViewResolver
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.M3u8Helper
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
|
||||
class WatchSB : ExtractorApi() {
|
||||
override val name: String
|
||||
get() = "WatchSB"
|
||||
override val mainUrl: String
|
||||
get() = "https://watchsb.com"
|
||||
override val requiresReferer: Boolean
|
||||
get() = false
|
||||
|
||||
override fun getUrl(url: String, referer: String?): List<ExtractorLink> {
|
||||
val response = app.get(
|
||||
url, interceptor = WebViewResolver(
|
||||
Regex("""master\.m3u8""")
|
||||
)
|
||||
)
|
||||
|
||||
val extractedLinksList = M3u8Helper().m3u8Generation(
|
||||
M3u8Helper.M3u8Stream(
|
||||
response.url,
|
||||
headers = response.headers.toMap()
|
||||
), true
|
||||
)
|
||||
.map { stream ->
|
||||
val qualityString = if ((stream.quality ?: 0) == 0) "" else "${stream.quality}p"
|
||||
ExtractorLink(
|
||||
name,
|
||||
"$name $qualityString",
|
||||
stream.streamUrl,
|
||||
url,
|
||||
getQualityFromName(stream.quality.toString()),
|
||||
true
|
||||
)
|
||||
}
|
||||
|
||||
return extractedLinksList
|
||||
}
|
||||
}
|
|
@ -9,6 +9,8 @@ import com.lagradost.cloudstream3.app
|
|||
import com.lagradost.cloudstream3.mapper
|
||||
import okhttp3.*
|
||||
import okhttp3.Headers.Companion.toHeaders
|
||||
import org.jsoup.Jsoup
|
||||
import org.jsoup.nodes.Document
|
||||
import java.io.File
|
||||
import java.net.URI
|
||||
import java.util.*
|
||||
|
@ -78,6 +80,7 @@ class AppResponse(
|
|||
val body by lazy { response.body }
|
||||
val code = response.code
|
||||
val headers = response.headers
|
||||
val document: Document by lazy { Jsoup.parse(text) }
|
||||
|
||||
/** Same as using mapper.readValue<T>() */
|
||||
inline fun <reified T : Any> mapped(): T {
|
||||
|
|
|
@ -741,9 +741,7 @@ class PlayerFragment : Fragment() {
|
|||
}
|
||||
|
||||
private fun safeReleasePlayer() {
|
||||
thread {
|
||||
simpleCache?.release()
|
||||
}
|
||||
simpleCache?.release()
|
||||
if (this::exoPlayer.isInitialized) {
|
||||
exoPlayer.release()
|
||||
}
|
||||
|
@ -1928,7 +1926,6 @@ class PlayerFragment : Fragment() {
|
|||
// torrentStream?.stopStream()
|
||||
// torrentStream = null
|
||||
|
||||
super.onDestroy()
|
||||
canEnterPipMode = false
|
||||
|
||||
savePositionInPlayer()
|
||||
|
@ -1938,6 +1935,7 @@ class PlayerFragment : Fragment() {
|
|||
|
||||
activity?.showSystemUI()
|
||||
activity?.requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_USER
|
||||
super.onDestroy()
|
||||
}
|
||||
|
||||
override fun onPause() {
|
||||
|
|
|
@ -58,13 +58,17 @@ fun getAndUnpack(string: String): String {
|
|||
return JsUnpacker(packedText).unpack() ?: string
|
||||
}
|
||||
|
||||
fun loadExtractor(url: String, referer: String?, callback: (ExtractorLink) -> Unit) {
|
||||
/**
|
||||
* Tries to load the appropriate extractor based on link, returns true if any extractor is loaded.
|
||||
* */
|
||||
fun loadExtractor(url: String, referer: String?, callback: (ExtractorLink) -> Unit) : Boolean {
|
||||
for (extractor in extractorApis) {
|
||||
if (url.startsWith(extractor.mainUrl)) {
|
||||
extractor.getSafeUrl(url, referer)?.forEach(callback)
|
||||
return
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
val extractorApis: Array<ExtractorApi> = arrayOf(
|
||||
|
@ -78,6 +82,7 @@ val extractorApis: Array<ExtractorApi> = arrayOf(
|
|||
Streamhub(),
|
||||
SBPlay(),
|
||||
FEmbed(),
|
||||
WatchSB(),
|
||||
|
||||
// dood extractors
|
||||
DoodToExtractor(),
|
||||
|
|
Loading…
Reference in a new issue