sora: added watchflx,hdmovies4u & solve #272, #273, #274

This commit is contained in:
hexated 2023-09-15 21:24:05 +07:00
parent 36e77332c5
commit 86f2735502
9 changed files with 207 additions and 187 deletions

View File

@ -6,10 +6,9 @@ import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
import com.lagradost.cloudstream3.extractors.Filesim import com.lagradost.cloudstream3.extractors.Filesim
import com.lagradost.cloudstream3.utils.* import com.lagradost.cloudstream3.utils.*
import org.jsoup.nodes.Element import org.jsoup.nodes.Element
import java.net.URLDecoder
class LayarKacaProvider : MainAPI() { class LayarKacaProvider : MainAPI() {
override var mainUrl = "https://tv3.lk21official.pro" override var mainUrl = "https://tv.lk21official.wiki"
private var seriesUrl = "https://tv1.nontondrama.click" private var seriesUrl = "https://tv1.nontondrama.click"
override var name = "LayarKaca" override var name = "LayarKaca"
override val hasMainPage = true override val hasMainPage = true

View File

@ -1,7 +1,7 @@
import org.jetbrains.kotlin.konan.properties.Properties import org.jetbrains.kotlin.konan.properties.Properties
// use an integer for version numbers // use an integer for version numbers
version = 169 version = 170
android { android {
defaultConfig { defaultConfig {

View File

@ -186,11 +186,6 @@ open class VCloud : ExtractorApi() {
} }
class HubcloudLol : VCloud() {
override val name = "Hubcloud"
override val mainUrl = "https://hubcloud.lol"
}
class Hubcloud : VCloud() { class Hubcloud : VCloud() {
override val name = "Hubcloud" override val name = "Hubcloud"
override val mainUrl = "https://hubcloud.in" override val mainUrl = "https://hubcloud.in"

View File

@ -580,6 +580,56 @@ object SoraExtractor : SoraStream() {
} }
suspend fun invokeWatchflx(
tmdbId: Int? = null,
season: Int? = null,
episode: Int? = null,
callback: (ExtractorLink) -> Unit
) {
val epsSlug = getEpisodeSlug(season, episode)
val cookies = getWatchflxCookies()
val url = if (season == null) {
"$watchflxAPI/browse/playmovie/$tmdbId/directplay"
} else {
"$watchflxAPI/Playseries/series/$tmdbId/directplay"
}
val res = app.get(url, cookies = cookies).document
val showUrl = if (season == null) {
res.selectFirst("iframe.movie_player")?.attr("src")
} else {
val seasonUrl =
res.select("ul.nav.nav-tabs.tabs-left li:matches(Season $season\$) a").attr("href")
val episodeUrl = app.get(
seasonUrl,
cookies = cookies
).document.select("div.thumb-nail-list a:contains(${epsSlug.second}:)").attr("href")
app.get(episodeUrl, cookies = cookies).document.selectFirst("iframe.movie_player")
?.attr("src")
}
val iframe = app.get(
showUrl ?: return, referer = "$watchflxAPI/"
).document.selectFirst("div#the_frame iframe")?.attr("src")
?.let { fixUrl(it, getBaseUrl(showUrl)) } ?: return
val video = app.get(iframe.replace("/loc/", "/pro/"), referer = iframe).text.let {
"""mp4_url\s*=\s*["'](.*)["'];""".toRegex().find(it)?.groupValues?.getOrNull(1)
}
callback.invoke(
ExtractorLink(
"Watchflx",
"Watchflx",
video ?: return,
"$watchflxAPI/",
Qualities.P1080.value,
INFER_TYPE
)
)
}
suspend fun invokeKimcartoon( suspend fun invokeKimcartoon(
title: String? = null, title: String? = null,
season: Int? = null, season: Int? = null,
@ -1144,7 +1194,13 @@ object SoraExtractor : SoraStream() {
val aTag = if (season == null) "Download Now" else "V-Cloud" val aTag = if (season == null) "Download Now" else "V-Cloud"
res.select("div.entry-content > $hTag:matches(1080p|2160p)").apmap { res.select("div.entry-content > $hTag:matches(1080p|2160p)").apmap {
val tags = """(?:1080p|2160p)(.*)""".toRegex().find(it.text())?.groupValues?.get(1)?.trim() val tags = """(?:1080p|2160p)(.*)""".toRegex().find(it.text())?.groupValues?.get(1)?.trim()
val href = it.nextElementSibling()?.select("a:contains($aTag)")?.attr("href") val href = it.nextElementSibling()?.select("a:contains($aTag)")?.attr("href")?.let { url ->
app.post(
"${getBaseUrl(url)}/red.php",
data = mapOf("link" to url),
referer = "$vegaMoviesAPI/"
).text.substringAfter("location.href = \"").substringBefore("\"")
}
val selector = if (season == null) "p a:contains(V-Cloud)" else "h4:matches(0?$episode) + p a:contains(V-Cloud)" val selector = if (season == null) "p a:contains(V-Cloud)" else "h4:matches(0?$episode) + p a:contains(V-Cloud)"
val server = app.get(href ?: return@apmap).document.selectFirst("div.entry-content > $selector") val server = app.get(href ?: return@apmap).document.selectFirst("div.entry-content > $selector")
?.attr("href") ?.attr("href")
@ -1233,6 +1289,45 @@ object SoraExtractor : SoraStream() {
} }
suspend fun invokeHdmovies4u(
title: String? = null,
imdbId: String? = null,
season: Int? = null,
episode: Int? = null,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit
) {
fun String.decodeLink(): String {
return base64Decode(this.substringAfterLast("/"))
}
val (seasonSlug, episodeSlug) = getEpisodeSlug(season, episode)
val media = app.get("$hdmovies4uAPI/?s=${if (season == null) imdbId else title}").document
.let {
val selector = if (season == null) "a" else "a:matches((?i)$title.*Season $season)"
it.selectFirst("div.gridxw.gridxe $selector")?.attr("href")
}
val selector = if (season == null) "1080p|2160p" else "(?i)Episode.*(?:1080p|2160p)"
app.get(
media ?: return
).document.select("section h4:matches($selector)").apmap { ele ->
val (tags, size) = ele.select("span").map {
it.text()
}.let { it[it.lastIndex - 1] to it.last().substringAfter("-").trim() }
val link = ele.nextElementSibling()?.select("a:contains(DriveTOT)")?.attr("href")
val iframe = bypassBqrecipes(link?.decodeLink() ?: return@apmap).let {
if (it?.contains("/pack/") == true) {
val href =
app.get(it).document.select("table tbody tr:contains(S${seasonSlug}E${episodeSlug}) a")
.attr("href")
bypassBqrecipes(href.decodeLink())
} else {
it
}
}
invokeDrivetot(iframe ?: return@apmap, tags, size, subtitleCallback, callback)
}
}
suspend fun invokeFwatayako( suspend fun invokeFwatayako(
imdbId: String? = null, imdbId: String? = null,
season: Int? = null, season: Int? = null,
@ -1859,25 +1954,12 @@ object SoraExtractor : SoraStream() {
invokeSmashyFfix(it.second, it.first, url, callback) invokeSmashyFfix(it.second, it.first, url, callback)
} }
it.first.contains("/gtop") -> { it.second.equals("Player FM", true) && !isAnime -> invokeSmashyFm(
invokeSmashyGtop(it.second, it.first, callback) it.second,
} it.first,
url,
it.first.contains("/dude_tv") -> { callback
invokeSmashyDude(it.second, it.first, callback) )
}
it.first.contains("/rip") -> {
invokeSmashyRip(it.second, it.first, subtitleCallback, callback)
}
it.first.contains("/im.php") && !isAnime -> {
invokeSmashyIm(it.second, it.first, subtitleCallback, callback)
}
it.first.contains("/rw.php") && !isAnime -> {
invokeSmashyRw(it.second, it.first, subtitleCallback, callback)
}
else -> return@apmap else -> return@apmap
} }

View File

@ -141,16 +141,6 @@ data class FDAds(
@JsonProperty("linkr") val linkr: String? = null, @JsonProperty("linkr") val linkr: String? = null,
) )
data class Smashy1Tracks(
@JsonProperty("file") val file: String? = null,
@JsonProperty("label") val label: String? = null,
)
data class Smashy1Source(
@JsonProperty("file") val file: String? = null,
@JsonProperty("tracks") val tracks: ArrayList<Smashy1Tracks>? = arrayListOf(),
)
data class WatchsomuchTorrents( data class WatchsomuchTorrents(
@JsonProperty("id") val id: Int? = null, @JsonProperty("id") val id: Int? = null,
@JsonProperty("movieId") val movieId: Int? = null, @JsonProperty("movieId") val movieId: Int? = null,
@ -240,11 +230,6 @@ data class CryMoviesResponse(
@JsonProperty("streams") val streams: List<CryMoviesStream>? = null, @JsonProperty("streams") val streams: List<CryMoviesStream>? = null,
) )
data class DudetvSources(
@JsonProperty("file") val file: String? = null,
@JsonProperty("title") val title: String? = null,
)
data class FmoviesResponses( data class FmoviesResponses(
@JsonProperty("result") val result: FmoviesResult? = null, @JsonProperty("result") val result: FmoviesResult? = null,
) )

View File

@ -38,6 +38,7 @@ import com.hexated.SoraExtractor.invokeSmashyStream
import com.hexated.SoraExtractor.invokeDumpStream import com.hexated.SoraExtractor.invokeDumpStream
import com.hexated.SoraExtractor.invokeEmovies import com.hexated.SoraExtractor.invokeEmovies
import com.hexated.SoraExtractor.invokeFourCartoon import com.hexated.SoraExtractor.invokeFourCartoon
import com.hexated.SoraExtractor.invokeHdmovies4u
import com.hexated.SoraExtractor.invokeJump1 import com.hexated.SoraExtractor.invokeJump1
import com.hexated.SoraExtractor.invokeMoment import com.hexated.SoraExtractor.invokeMoment
import com.hexated.SoraExtractor.invokeMultimovies import com.hexated.SoraExtractor.invokeMultimovies
@ -50,6 +51,7 @@ import com.hexated.SoraExtractor.invokeUhdmovies
import com.hexated.SoraExtractor.invokeVegamovies import com.hexated.SoraExtractor.invokeVegamovies
import com.hexated.SoraExtractor.invokeVidsrcto import com.hexated.SoraExtractor.invokeVidsrcto
import com.hexated.SoraExtractor.invokeWatchOnline import com.hexated.SoraExtractor.invokeWatchOnline
import com.hexated.SoraExtractor.invokeWatchflx
import com.hexated.SoraExtractor.invokeWatchsomuch import com.hexated.SoraExtractor.invokeWatchsomuch
import com.lagradost.cloudstream3.LoadResponse.Companion.addImdbId import com.lagradost.cloudstream3.LoadResponse.Companion.addImdbId
import com.lagradost.cloudstream3.LoadResponse.Companion.addTMDbId import com.lagradost.cloudstream3.LoadResponse.Companion.addTMDbId
@ -134,6 +136,8 @@ open class SoraStream : TmdbProvider() {
const val jump1API = "https://ca.jump1.net" const val jump1API = "https://ca.jump1.net"
const val vegaMoviesAPI = "https://vegamovies.im" const val vegaMoviesAPI = "https://vegamovies.im"
const val netflixAPI = "https://m.netflixmirror.com" const val netflixAPI = "https://m.netflixmirror.com"
const val hdmovies4uAPI = "https://hdmovies4u.name"
const val watchflxAPI = "https://watchflx.tv"
// INDEX SITE // INDEX SITE
const val dahmerMoviesAPI = "https://edytjedhgmdhm.abfhaqrhbnf.workers.dev" const val dahmerMoviesAPI = "https://edytjedhgmdhm.abfhaqrhbnf.workers.dev"
@ -748,6 +752,19 @@ open class SoraStream : TmdbProvider() {
res.episode, res.episode,
callback callback
) )
},
{
if (!res.isAnime) invokeHdmovies4u(
res.title,
res.imdbId,
res.season,
res.episode,
subtitleCallback,
callback
)
},
{
if (!res.isAnime) invokeWatchflx(res.id, res.season, res.episode, callback)
} }
) )

View File

@ -34,6 +34,7 @@ import com.hexated.SoraExtractor.invokePrimewire
import com.hexated.SoraExtractor.invokeVidSrc import com.hexated.SoraExtractor.invokeVidSrc
import com.hexated.SoraExtractor.invokeVidsrcto import com.hexated.SoraExtractor.invokeVidsrcto
import com.hexated.SoraExtractor.invokeWatchOnline import com.hexated.SoraExtractor.invokeWatchOnline
import com.hexated.SoraExtractor.invokeWatchflx
import com.hexated.SoraExtractor.invokeWatchsomuch import com.hexated.SoraExtractor.invokeWatchsomuch
import com.lagradost.cloudstream3.SubtitleFile import com.lagradost.cloudstream3.SubtitleFile
import com.lagradost.cloudstream3.argamap import com.lagradost.cloudstream3.argamap
@ -320,6 +321,14 @@ class SoraStreamLite : SoraStream() {
callback callback
) )
}, },
{
if (!res.isAnime) invokeWatchflx(
res.id,
res.season,
res.episode,
callback
)
},
{ {
if(!res.isAnime) invoke2embed( if(!res.isAnime) invoke2embed(
res.imdbId, res.imdbId,

View File

@ -21,6 +21,5 @@ class SoraStreamPlugin: Plugin() {
registerExtractorAPI(VCloud()) registerExtractorAPI(VCloud())
registerExtractorAPI(Pixeldra()) registerExtractorAPI(Pixeldra())
registerExtractorAPI(Hubcloud()) registerExtractorAPI(Hubcloud())
registerExtractorAPI(HubcloudLol())
} }
} }

View File

@ -9,10 +9,12 @@ import com.hexated.SoraStream.Companion.crunchyrollAPI
import com.hexated.SoraStream.Companion.filmxyAPI import com.hexated.SoraStream.Companion.filmxyAPI
import com.hexated.SoraStream.Companion.fmoviesAPI import com.hexated.SoraStream.Companion.fmoviesAPI
import com.hexated.SoraStream.Companion.gdbot import com.hexated.SoraStream.Companion.gdbot
import com.hexated.SoraStream.Companion.hdmovies4uAPI
import com.hexated.SoraStream.Companion.malsyncAPI import com.hexated.SoraStream.Companion.malsyncAPI
import com.hexated.SoraStream.Companion.smashyStreamAPI import com.hexated.SoraStream.Companion.smashyStreamAPI
import com.hexated.SoraStream.Companion.tvMoviesAPI import com.hexated.SoraStream.Companion.tvMoviesAPI
import com.hexated.SoraStream.Companion.watchOnlineAPI import com.hexated.SoraStream.Companion.watchOnlineAPI
import com.hexated.SoraStream.Companion.watchflxAPI
import com.hexated.SoraStream.Companion.watchhubApi import com.hexated.SoraStream.Companion.watchhubApi
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.APIHolder.getCaptchaToken import com.lagradost.cloudstream3.APIHolder.getCaptchaToken
@ -43,6 +45,8 @@ import javax.crypto.spec.SecretKeySpec
import kotlin.collections.ArrayList import kotlin.collections.ArrayList
import kotlin.math.min import kotlin.math.min
var watchflxCookies: Map<String, String>? = null
var filmxyCookies: Map<String,String>? = null
val bflixChipperKey = base64DecodeAPI("Yjc=ejM=TzA=YTk=WHE=WnU=bXU=RFo=") val bflixChipperKey = base64DecodeAPI("Yjc=ejM=TzA=YTk=WHE=WnU=bXU=RFo=")
const val bflixKey = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" const val bflixKey = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
val encodedIndex = arrayOf( val encodedIndex = arrayOf(
@ -484,158 +488,29 @@ suspend fun invokeSmashyFfix(
} }
suspend fun invokeSmashyGtop( suspend fun invokeSmashyFm(
name: String, name: String,
url: String, url: String,
callback: (ExtractorLink) -> Unit ref: String,
) {
val doc = app.get(url).document
val script = doc.selectFirst("script:containsData(var secret)")?.data() ?: return
val secret =
script.substringAfter("secret = \"").substringBefore("\";").let { base64Decode(it) }
val key = script.substringAfter("token = \"").substringBefore("\";")
val source = app.get(
"$secret$key",
headers = mapOf(
"X-Requested-With" to "XMLHttpRequest"
)
).parsedSafe<Smashy1Source>() ?: return
val videoUrl = base64Decode(source.file ?: return)
if (videoUrl.contains("/bug")) return
val quality =
Regex("(\\d{3,4})[Pp]").find(videoUrl)?.groupValues?.getOrNull(1)?.toIntOrNull()
?: Qualities.P720.value
callback.invoke(
ExtractorLink(
"Smashy [$name]",
"Smashy [$name]",
videoUrl,
"",
quality,
videoUrl.contains(".m3u8")
)
)
}
suspend fun invokeSmashyDude(
name: String,
url: String,
callback: (ExtractorLink) -> Unit
) {
val script =
app.get(url).document.selectFirst("script:containsData(player =)")?.data() ?: return
val source = Regex("file:\\s*(\\[.*]),").find(script)?.groupValues?.get(1) ?: return
tryParseJson<ArrayList<DudetvSources>>(source)?.filter { it.title == "English" }?.map {
M3u8Helper.generateM3u8(
"Smashy [Player 2]",
it.file ?: return@map,
""
).forEach(callback)
}
}
suspend fun invokeSmashyRip(
name: String,
url: String,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit, callback: (ExtractorLink) -> Unit,
) { ) {
val script = fun String.removeProxy(): String {
app.get(url).document.selectFirst("script:containsData(player =)")?.data() ?: return return if (this.contains("proxy")) {
"https${this.substringAfterLast("https")}"
val source = Regex("file:\\s*\"([^\"]+)").find(script)?.groupValues?.get(1) } else {
val subtitle = Regex("subtitle:\\s*\"([^\"]+)").find(script)?.groupValues?.get(1) this
}
source?.split(",")?.map { links ->
val quality = Regex("\\[(\\d+)]").find(links)?.groupValues?.getOrNull(1)?.trim()
val link = links.removePrefix("[$quality]").substringAfter("dev/").trim()
if (link.isEmpty()) return@map
callback.invoke(
ExtractorLink(
"Smashy [$name]",
"Smashy [$name]",
link,
"",
quality?.toIntOrNull() ?: return@map,
isM3u8 = true,
)
)
} }
subtitle?.replace("<br>", "")?.split(",")?.map { sub -> val res = app.get(url, referer = ref).text
val lang = Regex("\\[(.*?)]").find(sub)?.groupValues?.getOrNull(1)?.trim() val source = Regex("['\"]?file['\"]?:\\s*\"([^\"]+)").find(res)?.groupValues?.get(1) ?: return
val link = sub.removePrefix("[$lang]")
subtitleCallback.invoke(
SubtitleFile(
lang.orEmpty().ifEmpty { return@map },
link
)
)
}
}
suspend fun invokeSmashyIm(
name: String,
url: String,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit,
) {
val script =
app.get(url).document.selectFirst("script:containsData(player =)")?.data() ?: return
val sources =
Regex("['\"]?file['\"]?:\\s*\"([^\"]+)").find(script)?.groupValues?.get(1) ?: return
val subtitles =
Regex("['\"]?subtitle['\"]?:\\s*\"([^\"]+)").find(script)?.groupValues?.get(1) ?: return
M3u8Helper.generateM3u8( M3u8Helper.generateM3u8(
"Smashy [$name]", "Smashy [$name]",
sources, source.removeProxy(),
"" "https://vidstream.pro/"
).forEach(callback) ).forEach(callback)
subtitles.split(",").map { sub ->
val lang = Regex("\\[(.*?)]").find(sub)?.groupValues?.getOrNull(1)?.trim()
val trimmedSubLink = sub.removePrefix("[$lang]").trim().substringAfter("?url=")
subtitleCallback.invoke(
SubtitleFile(
lang.takeIf { !it.isNullOrEmpty() } ?: return@map,
trimmedSubLink
)
)
}
}
suspend fun invokeSmashyRw(
name: String,
url: String,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit,
) {
val res = app.get(url).document
val video = res.selectFirst("media-player")?.attr("src")
M3u8Helper.generateM3u8(
"Smashy [$name]",
video ?: return,
""
).forEach(callback)
res.select("track").map { track ->
subtitleCallback.invoke(
SubtitleFile(
track.attr("label"),
track.attr("src"),
)
)
}
} }
suspend fun getDumpIdAndType(title: String?, year: Int?, season: Int?): Pair<String?, Int?> { suspend fun getDumpIdAndType(title: String?, year: Int?, season: Int?): Pair<String?, Int?> {
@ -696,6 +571,52 @@ suspend fun fetchDumpEpisodes(id: String, type: String, episode: Int?): EpisodeV
} }
} }
suspend fun invokeDrivetot(
url: String,
tags: String? = null,
size: String? = null,
subtitleCallback: (SubtitleFile) -> Unit,
callback: (ExtractorLink) -> Unit,
) {
val res = app.get(url)
val data = res.document.select("form input").associate { it.attr("name") to it.attr("value") }
app.post(res.url, data = data, cookies = res.cookies).document.select("div.card-body a").apmap { ele ->
val href = base64Decode(ele.attr("href").substringAfterLast("/")).let {
if(it.contains("hubcloud.lol")) it.replace("hubcloud.lol", "hubcloud.in") else it
}
loadExtractor(href, "$hdmovies4uAPI/", subtitleCallback) { link ->
callback.invoke(
ExtractorLink(
link.source,
"${link.name} $tags [$size]",
link.url,
link.referer,
link.quality,
link.type,
link.headers,
link.extractorData
)
)
}
}
}
suspend fun bypassBqrecipes(url: String): String? {
var res = app.get(url)
var location = res.text.substringAfter(".replace('").substringBefore("');")
var cookies = res.cookies
res = app.get(location, cookies = cookies)
cookies = cookies + res.cookies
val document = res.document
location = document.select("form#recaptcha").attr("action")
val data =
document.select("form#recaptcha input").associate { it.attr("name") to it.attr("value") }
res = app.post(location, data = data, cookies = cookies)
location = res.document.selectFirst("a#messagedown")?.attr("href") ?: return null
cookies = (cookies + res.cookies).minus("var")
return app.get(location, cookies = cookies, allowRedirects = false).headers["location"]
}
suspend fun bypassOuo(url: String?): String? { suspend fun bypassOuo(url: String?): String? {
var res = session.get(url ?: return null) var res = session.get(url ?: return null)
run lit@{ run lit@{
@ -915,8 +836,6 @@ suspend fun getTvMoviesServer(url: String, season: Int?, episode: Int?): Pair<St
}.lastOrNull() }.lastOrNull()
} }
} }
var filmxyCookies: Map<String,String>? = null
suspend fun getFilmxyCookies(url: String) = filmxyCookies ?: fetchFilmxyCookies(url).also { filmxyCookies = it } suspend fun getFilmxyCookies(url: String) = filmxyCookies ?: fetchFilmxyCookies(url).also { filmxyCookies = it }
suspend fun fetchFilmxyCookies(url: String): Map<String, String> { suspend fun fetchFilmxyCookies(url: String): Map<String, String> {
@ -957,6 +876,21 @@ suspend fun fetchFilmxyCookies(url: String): Map<String, String> {
return cookieJar.plus(defaultCookies) return cookieJar.plus(defaultCookies)
} }
suspend fun getWatchflxCookies() = watchflxCookies ?: fetchWatchflxCookies().also { watchflxCookies = it }
suspend fun fetchWatchflxCookies(): Map<String, String> {
session.get(watchflxAPI)
val cookies = session.baseClient.cookieJar.loadForRequest(watchflxAPI.toHttpUrl())
.associate { it.name to it.value }
val loginUrl = "$watchflxAPI/cookie-based-login"
session.post(
loginUrl, data = mapOf(
"continue_as_temp" to "true"
), cookies = cookies, headers = mapOf("X-Requested-With" to "XMLHttpRequest")
)
return session.baseClient.cookieJar.loadForRequest(loginUrl.toHttpUrl()).associate { it.name to it.value }
}
fun Document.findTvMoviesIframe(): String? { fun Document.findTvMoviesIframe(): String? {
return this.selectFirst("script:containsData(var seconds)")?.data()?.substringAfter("href='") return this.selectFirst("script:containsData(var seconds)")?.data()?.substringAfter("href='")
?.substringBefore("'>") ?.substringBefore("'>")