small fix

This commit is contained in:
LagradOst 2022-07-28 17:49:44 +02:00
parent 4ac7e0c967
commit cd569b44c8
7 changed files with 102 additions and 367 deletions

View file

@ -17,6 +17,8 @@ class NineAnimeProvider : MainAPI() {
override val supportedTypes = setOf(TvType.Anime) override val supportedTypes = setOf(TvType.Anime)
override val hasQuickSearch = true override val hasQuickSearch = true
// taken from https://github.com/saikou-app/saikou/blob/b35364c8c2a00364178a472fccf1ab72f09815b4/app/src/main/java/ani/saikou/parsers/anime/NineAnime.kt
// GNU General Public License v3.0 https://github.com/saikou-app/saikou/blob/main/LICENSE.md
companion object { companion object {
fun getDubStatus(title: String): DubStatus { fun getDubStatus(title: String): DubStatus {
return if (title.contains("(dub)", ignoreCase = true)) { return if (title.contains("(dub)", ignoreCase = true)) {
@ -31,17 +33,17 @@ class NineAnimeProvider : MainAPI() {
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/" "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
private const val cipherKey = "rTKp3auwu0ULA6II" private const val cipherKey = "rTKp3auwu0ULA6II"
private fun encodeVrf(text: String): String { fun encodeVrf(text: String, mainKey: String): String {
return encode( return encode(
encrypt( encrypt(
cipher(cipherKey, encode(text)), cipher(mainKey, encode(text)),
nineAnimeKey nineAnimeKey
).replace("""=+$""".toRegex(), "") ).replace("""=+$""".toRegex(), "")
) )
} }
private fun decodeVrf(text: String): String { fun decodeVrf(text: String, mainKey: String): String {
return decode(cipher(cipherKey, decrypt(text, nineAnimeKey))) return decode(cipher(mainKey, decrypt(text, nineAnimeKey)))
} }
fun encrypt(input: String, key: String): String { fun encrypt(input: String, key: String): String {
@ -129,7 +131,7 @@ class NineAnimeProvider : MainAPI() {
} }
} }
private fun encode(input: String): String = fun encode(input: String): String =
java.net.URLEncoder.encode(input, "utf-8").replace("+", "%20") java.net.URLEncoder.encode(input, "utf-8").replace("+", "%20")
private fun decode(input: String): String = java.net.URLDecoder.decode(input, "utf-8") private fun decode(input: String): String = java.net.URLDecoder.decode(input, "utf-8")
@ -192,7 +194,7 @@ class NineAnimeProvider : MainAPI() {
) )
override suspend fun quickSearch(query: String): List<SearchResponse>? { override suspend fun quickSearch(query: String): List<SearchResponse>? {
val vrf = encodeVrf(query) val vrf = encodeVrf(query, cipherKey)
val url = val url =
"$mainUrl/ajax/anime/search?keyword=$query&vrf=$vrf" "$mainUrl/ajax/anime/search?keyword=$query&vrf=$vrf"
val response = app.get(url).parsedSafe<QuickSearchResponse>() val response = app.get(url).parsedSafe<QuickSearchResponse>()
@ -207,7 +209,7 @@ class NineAnimeProvider : MainAPI() {
} }
override suspend fun search(query: String): List<SearchResponse> { override suspend fun search(query: String): List<SearchResponse> {
val vrf = encodeVrf(query) val vrf = encodeVrf(query, cipherKey)
//?language%5B%5D=${if (selectDub) "dubbed" else "subbed"}& //?language%5B%5D=${if (selectDub) "dubbed" else "subbed"}&
val url = val url =
"$mainUrl/filter?keyword=${encode(query)}&vrf=${vrf}&page=1" "$mainUrl/filter?keyword=${encode(query)}&vrf=${vrf}&page=1"
@ -236,7 +238,8 @@ class NineAnimeProvider : MainAPI() {
?: throw ErrorLoadingException("Could not find title") ?: throw ErrorLoadingException("Could not find title")
val body = val body =
app.get("$mainUrl/ajax/episode/list/$id?vrf=${encodeVrf(id)}").parsed<Response>().html app.get("$mainUrl/ajax/episode/list/$id?vrf=${encodeVrf(id, cipherKey)}")
.parsed<Response>().html
val subEpisodes = ArrayList<Episode>() val subEpisodes = ArrayList<Episode>()
val dubEpisodes = ArrayList<Episode>() val dubEpisodes = ArrayList<Episode>()
@ -253,7 +256,7 @@ class NineAnimeProvider : MainAPI() {
ids.getOrNull(1)?.let { dub -> ids.getOrNull(1)?.let { dub ->
dubEpisodes.add( dubEpisodes.add(
Episode( Episode(
"$mainUrl/ajax/server/list/$dub?vrf=${encodeVrf(dub)}", "$mainUrl/ajax/server/list/$dub?vrf=${encodeVrf(dub, cipherKey)}",
epTitle, epTitle,
episode = epNum episode = epNum
) )
@ -262,7 +265,7 @@ class NineAnimeProvider : MainAPI() {
ids.getOrNull(0)?.let { sub -> ids.getOrNull(0)?.let { sub ->
subEpisodes.add( subEpisodes.add(
Episode( Episode(
"$mainUrl/ajax/server/list/$sub?vrf=${encodeVrf(sub)}", "$mainUrl/ajax/server/list/$sub?vrf=${encodeVrf(sub, cipherKey)}",
epTitle, epTitle,
episode = epNum episode = epNum
) )
@ -321,7 +324,7 @@ class NineAnimeProvider : MainAPI() {
//TODO 9anime outro into {"status":200,"result":{"url":"","skip_data":{"intro_begin":67,"intro_end":154,"outro_begin":1337,"outro_end":1415,"count":3}},"message":"","messages":[]} //TODO 9anime outro into {"status":200,"result":{"url":"","skip_data":{"intro_begin":67,"intro_end":154,"outro_begin":1337,"outro_end":1415,"count":3}},"message":"","messages":[]}
private suspend fun getEpisodeLinks(id: String): Links? { private suspend fun getEpisodeLinks(id: String): Links? {
return app.get("$mainUrl/ajax/server/$id?vrf=${encodeVrf(id)}").parsedSafe() return app.get("$mainUrl/ajax/server/$id?vrf=${encodeVrf(id, cipherKey)}").parsedSafe()
} }
override suspend fun loadLinks( override suspend fun loadLinks(
@ -338,7 +341,7 @@ class NineAnimeProvider : MainAPI() {
val name = it.text() val name = it.text()
val encodedStreamUrl = val encodedStreamUrl =
getEpisodeLinks(it.attr("data-link-id"))?.result?.url ?: return@apmap getEpisodeLinks(it.attr("data-link-id"))?.result?.url ?: return@apmap
val url = decodeVrf(encodedStreamUrl) val url = decodeVrf(encodedStreamUrl, cipherKey)
if (!loadExtractor(url, mainUrl, subtitleCallback, callback)) { if (!loadExtractor(url, mainUrl, subtitleCallback, callback)) {
callback( callback(
ExtractorLink( ExtractorLink(

View file

@ -1,82 +1,7 @@
package com.lagradost.cloudstream3.extractors package com.lagradost.cloudstream3.extractors
import com.fasterxml.jackson.annotation.JsonProperty open class Mcloud : WcoStream() {
import com.lagradost.cloudstream3.USER_AGENT
import com.lagradost.cloudstream3.apmap
import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.extractors.WcoStream.Companion.cipher
import com.lagradost.cloudstream3.extractors.WcoStream.Companion.encrypt
import com.lagradost.cloudstream3.extractors.WcoStream.Companion.keytwo
import com.lagradost.cloudstream3.extractors.helper.WcoHelper.Companion.getNewWcoKey
import com.lagradost.cloudstream3.extractors.helper.WcoHelper.Companion.getWcoKey
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8
open class Mcloud : ExtractorApi() {
override var name = "Mcloud" override var name = "Mcloud"
override var mainUrl = "https://mcloud.to" override var mainUrl = "https://mcloud.to"
override val requiresReferer = true override val requiresReferer = true
val headers = mapOf(
"Host" to "mcloud.to",
"User-Agent" to USER_AGENT,
"Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
"Accept-Language" to "en-US,en;q=0.5",
"DNT" to "1",
"Connection" to "keep-alive",
"Upgrade-Insecure-Requests" to "1",
"Sec-Fetch-Dest" to "iframe",
"Sec-Fetch-Mode" to "navigate",
"Sec-Fetch-Site" to "cross-site",
"Referer" to "https://animekisa.in/", //Referer works for wco and animekisa, probably with others too
"Pragma" to "no-cache",
"Cache-Control" to "no-cache",)
private val key = "LCbu3iYC7ln24K7P" // key credits @Modder4869
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
val id = url.substringAfter("e/").substringAfter("embed/").substringBefore("?")
val keys = getNewWcoKey()
keytwo = keys?.encryptKey ?: return null
val encryptedid = encrypt(cipher(keys.cipherkey!!, encrypt(id))).replace("/", "_").replace("=","")
val link = "$mainUrl/mediainfo/$encryptedid?key=${keys.mainKey}"
val response = app.get(link, referer = "https://animekisa.in/").text
if(response.startsWith("<!DOCTYPE html>")) {
// TODO decrypt html for link
return emptyList()
}
data class SourcesMcloud (
@JsonProperty("file" ) val file : String
)
data class MediaMcloud (
@JsonProperty("sources" ) val sources : ArrayList<SourcesMcloud> = arrayListOf()
)
data class DataMcloud (
@JsonProperty("media" ) val media : MediaMcloud? = MediaMcloud()
)
data class JsonMcloud (
@JsonProperty("status" ) val status : Int? = null,
@JsonProperty("data" ) val data : DataMcloud = DataMcloud()
)
val mapped = parseJson<JsonMcloud>(response)
val sources = mutableListOf<ExtractorLink>()
val checkfile = mapped.status == 200
if (checkfile)
mapped.data.media?.sources?.apmap {
if (it.file.contains("m3u8")) {
sources.addAll(
generateM3u8(
name,
it.file,
url,
headers = mapOf("Referer" to url)
)
)
}
}
return sources
}
} }

View file

@ -1,15 +1,13 @@
package com.lagradost.cloudstream3.extractors package com.lagradost.cloudstream3.extractors
import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.apmap import com.lagradost.cloudstream3.ErrorLoadingException
import com.lagradost.cloudstream3.animeproviders.NineAnimeProvider.Companion.cipher
import com.lagradost.cloudstream3.animeproviders.NineAnimeProvider.Companion.encrypt
import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.extractors.helper.WcoHelper.Companion.getNewWcoKey
import com.lagradost.cloudstream3.extractors.helper.WcoHelper.Companion.getWcoKey
import com.lagradost.cloudstream3.utils.ExtractorApi import com.lagradost.cloudstream3.utils.ExtractorApi
import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8
import com.lagradost.cloudstream3.utils.Qualities import com.lagradost.cloudstream3.utils.Qualities
import com.lagradost.cloudstream3.utils.getQualityFromName
class Vidstreamz : WcoStream() { class Vidstreamz : WcoStream() {
override var mainUrl = "https://vidstreamz.online" override var mainUrl = "https://vidstreamz.online"
@ -51,173 +49,79 @@ class VizcloudCloud : WcoStream() {
override var mainUrl = "https://vizcloud.cloud" override var mainUrl = "https://vizcloud.cloud"
} }
class VizcloudSite : WcoStream() {
override var mainUrl = "https://vizcloud.site"
}
open class WcoStream : ExtractorApi() { open class WcoStream : ExtractorApi() {
override var name = "VidStream" // Cause works for animekisa and wco override var name = "VidStream" // Cause works for animekisa and wco
override var mainUrl = "https://vidstream.pro" override var mainUrl = "https://vidstream.pro"
override val requiresReferer = false override val requiresReferer = false
private val regex = Regex("(.+?/)e(?:mbed)?/([a-zA-Z0-9]+)")
companion object { companion object {
var keytwo = "" // taken from https://github.com/saikou-app/saikou/blob/b35364c8c2a00364178a472fccf1ab72f09815b4/app/src/main/java/ani/saikou/parsers/anime/extractors/VizCloud.kt
fun encrypt(input: String): String { // GNU General Public License v3.0 https://github.com/saikou-app/saikou/blob/main/LICENSE.md
if (input.any { it.code >= 256 }) throw Exception("illegal characters!") private var lastChecked = 0L
var output = "" private const val jsonLink =
for (i in input.indices step 3) { "https://raw.githubusercontent.com/chenkaslowankiya/BruhFlow/main/keys.json"
val a = intArrayOf(-1, -1, -1, -1) private var cipherKey: VizCloudKey? = null
a[0] = input[i].code shr 2 suspend fun getKey(): VizCloudKey {
a[1] = (3 and input[i].code) shl 4 cipherKey =
if (input.length > i + 1) { if (cipherKey != null && (lastChecked - System.currentTimeMillis()) < 1000 * 60 * 30) cipherKey!!
a[1] = a[1] or (input[i + 1].code shr 4)
a[2] = (15 and input[i + 1].code) shl 2
}
if (input.length > i + 2) {
a[2] = a[2] or (input[i + 2].code shr 6)
a[3] = 63 and input[i + 2].code
}
for (n in a) {
if (n == -1) output += "="
else { else {
if (n in 0..63) output += keytwo[n] lastChecked = System.currentTimeMillis()
app.get(jsonLink).parsed()
} }
} return cipherKey!!
}
return output;
} }
fun cipher(inputOne: String, inputTwo: String): String { data class VizCloudKey(
val arr = IntArray(256) { it } @JsonProperty("cipherKey") val cipherKey: String,
var output = "" @JsonProperty("mainKey") val mainKey: String,
var u = 0 @JsonProperty("encryptKey") val encryptKey: String,
var r: Int @JsonProperty("dashTable") val dashTable: String
for (a in arr.indices) { )
u = (u + arr[a] + inputOne[a % inputOne.length].code) % 256
r = arr[a] private const val baseTable =
arr[a] = arr[u] "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+=/_"
arr[u] = r
} private fun dashify(id: String, dashTable: String): String {
u = 0 val table = dashTable.split(" ")
var c = 0 return id.mapIndexedNotNull { i, c ->
for (f in inputTwo.indices) { table.getOrNull((baseTable.indexOf(c) * 16) + (i % 16))
c = (c + f) % 256 }.joinToString("-")
u = (u + arr[c]) % 256
r = arr[c]
arr[c] = arr[u]
arr[u] = r
output += (inputTwo[f].code xor arr[(arr[c] + arr[u]) % 256]).toChar()
}
return output
} }
} }
private val key = "LCbu3iYC7ln24K7P" // key credits @Modder4869
//private val key = "LCbu3iYC7ln24K7P" // key credits @Modder4869
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> { override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
val baseUrl = url.split("/e/")[0] val group = regex.find(url)?.groupValues!!
val (Id) = (Regex("/e/(.*?)?domain").find(url)?.destructured ?: Regex("""/e/(.*)""").find( val host = group[1]
url val viz = getKey()
)?.destructured) ?: return emptyList() val id = encrypt(
// val (skey) = Regex("""skey\s=\s['"](.*?)['"];""").find(html)?.destructured cipher(
// ?: return emptyList() viz.cipherKey,
val keys = getNewWcoKey() encrypt(group[2], viz.encryptKey).also { println(it) }
keytwo = keys?.encryptKey ?: return emptyList() ).also { println(it) },
val encryptedID = encrypt(cipher(keys.cipherkey!!, encrypt(Id))).replace("/", "_").replace("=","") viz.encryptKey
val apiLink = "$baseUrl/mediainfo/$encryptedID?key=${keys.mainKey}" ).also { println(it) }
val referrer = "$baseUrl/e/$Id?domain=wcostream.cc"
data class SourcesWco ( val link =
@JsonProperty("file" ) val file : String "${host}mediainfo/${dashify(id, viz.dashTable)}?key=${viz.mainKey}" //
) val response = app.get(link, referer = referer)
data class MediaWco ( data class Sources(@JsonProperty("file") val file: String)
@JsonProperty("sources" ) val sources : ArrayList<SourcesWco> = arrayListOf() data class Media(@JsonProperty("sources") val sources: List<Sources>)
) data class Data(@JsonProperty("media") val media: Media)
data class Response(@JsonProperty("data") val data: Data)
data class DataWco (
@JsonProperty("media" ) val media : MediaWco? = MediaWco()
)
data class WcoResponse ( if (!response.text.startsWith("{")) throw ErrorLoadingException("Seems like 9Anime kiddies changed stuff again, Go touch some grass for bout an hour Or use a different Server")
@JsonProperty("status" ) val status : Int? = null, return response.parsed<Response>().data.media.sources.map {
@JsonProperty("data" ) val data : DataWco? = DataWco() ExtractorLink(name, it.file,it.file,host,Qualities.Unknown.value,it.file.contains(".m3u8"))
) }
val mapped = app.get(apiLink, headers = mapOf("Referer" to referrer)).parsed<WcoResponse>()
val sources = mutableListOf<ExtractorLink>()
val check = mapped.status == 200
if (check) {
mapped.data?.media?.sources?.forEach {
if (mainUrl == "https://vizcloud2.ru" || mainUrl == "https://vizcloud.online") {
if (it.file.contains("vizcloud2.ru") || it.file.contains("vizcloud.online")) {
// Had to do this thing 'cause "list.m3u8#.mp4" gives 404 error so no quality is added
val link1080 = it.file.replace("list.m3u8#.mp4", "H4/v.m3u8")
val link720 = it.file.replace("list.m3u8#.mp4", "H3/v.m3u8")
val link480 = it.file.replace("list.m3u8#.mp4", "H2/v.m3u8")
val link360 = it.file.replace("list.m3u8#.mp4", "H1/v.m3u8")
val linkauto = it.file.replace("#.mp4", "")
listOf(
link1080,
link720,
link480,
link360,
linkauto
).apmap { serverurl ->
val testurl = app.get(serverurl, headers = mapOf("Referer" to url)).text
if (testurl.contains("EXTM3")) {
val quality = when {
serverurl.contains("H4") -> "1080p"
serverurl.contains("H3") -> "720p"
serverurl.contains("H2") -> "480p"
serverurl.contains("H1") -> "360p"
else -> "Auto"
}
sources.add(
ExtractorLink(
"VidStream",
"VidStream",
serverurl,
url,
getQualityFromName(quality),
true,
)
)
}
}
}
} else if (
arrayOf(
"https://vidstream.pro",
"https://vidstreamz.online",
"https://vizcloud2.online",
"https://vizcloud.xyz",
"https://vizcloud.live",
"https://vizcloud.info",
"https://mwvn.vizcloud.info",
"https://vizcloud.digital",
"https://vizcloud.cloud"
).contains(mainUrl)
) {
if (it.file.contains("m3u8")) {
sources.addAll(
generateM3u8(
name,
it.file.replace("#.mp4", ""),
url,
headers = mapOf("Referer" to url)
)
)
} else {
sources.add(
ExtractorLink(
name,
name = name,
it.file,
"",
Qualities.P720.value,
false
)
)
}
}
}
}
return sources
} }
} }

View file

@ -2,6 +2,9 @@ package com.lagradost.cloudstream3.movieproviders
import com.fasterxml.jackson.annotation.JsonProperty import com.fasterxml.jackson.annotation.JsonProperty
import com.lagradost.cloudstream3.* import com.lagradost.cloudstream3.*
import com.lagradost.cloudstream3.animeproviders.NineAnimeProvider.Companion.decodeVrf
import com.lagradost.cloudstream3.animeproviders.NineAnimeProvider.Companion.encode
import com.lagradost.cloudstream3.animeproviders.NineAnimeProvider.Companion.encodeVrf
import com.lagradost.cloudstream3.utils.AppUtils.parseJson import com.lagradost.cloudstream3.utils.AppUtils.parseJson
import com.lagradost.cloudstream3.utils.ExtractorLink import com.lagradost.cloudstream3.utils.ExtractorLink
import com.lagradost.cloudstream3.utils.loadExtractor import com.lagradost.cloudstream3.utils.loadExtractor
@ -62,113 +65,8 @@ open class BflixProvider : MainAPI() {
return HomePageResponse(items) return HomePageResponse(items)
} }
//Credits to https://github.com/jmir1
private val key =
"5uLKesbh0nkrpPq9VwMC6+tQBdomjJ4HNl/fWOSiREvAYagT8yIG7zx2D13UZFXc" //key credits to @Modder4869
private fun getVrf(id: String): String? {
val reversed = ue(encode(id) + "0000000").slice(0..5).reversed()
return reversed + ue(je(reversed, encode(id)?.replace("+", "%20") ?: return null)).replace(
"""=+$""".toRegex(),
""
)
}
private fun getLink(url: String): String? {
val i = url.slice(0..5)
val n = url.slice(6..url.lastIndex)
return decode(je(i, ze(n)))
}
private fun ue(input: String): String {
if (input.any { it.code >= 256 }) throw Exception("illegal characters!")
var output = ""
for (i in input.indices step 3) {
val a = intArrayOf(-1, -1, -1, -1)
a[0] = input[i].code shr 2
a[1] = (3 and input[i].code) shl 4
if (input.length > i + 1) {
a[1] = a[1] or (input[i + 1].code shr 4)
a[2] = (15 and input[i + 1].code) shl 2
}
if (input.length > i + 2) {
a[2] = a[2] or (input[i + 2].code shr 6)
a[3] = 63 and input[i + 2].code
}
for (n in a) {
if (n == -1) output += "="
else {
if (n in 0..63) output += key[n]
}
}
}
return output
}
private fun je(inputOne: String, inputTwo: String): String {
val arr = IntArray(256) { it }
var output = ""
var u = 0
var r: Int
for (a in arr.indices) {
u = (u + arr[a] + inputOne[a % inputOne.length].code) % 256
r = arr[a]
arr[a] = arr[u]
arr[u] = r
}
u = 0
var c = 0
for (f in inputTwo.indices) {
c = (c + f) % 256
u = (u + arr[c]) % 256
r = arr[c]
arr[c] = arr[u]
arr[u] = r
output += (inputTwo[f].code xor arr[(arr[c] + arr[u]) % 256]).toChar()
}
return output
}
private fun ze(input: String): String {
val t = if (input.replace("""[\t\n\f\r]""".toRegex(), "").length % 4 == 0) {
input.replace("""/==?$/""".toRegex(), "")
} else input
if (t.length % 4 == 1 || t.contains("""[^+/0-9A-Za-z]""".toRegex())) throw Exception("bad input")
var i: Int
var r = ""
var e = 0
var u = 0
for (o in t.indices) {
e = e shl 6
i = key.indexOf(t[o])
e = e or i
u += 6
if (24 == u) {
r += ((16711680 and e) shr 16).toChar()
r += ((65280 and e) shr 8).toChar()
r += (255 and e).toChar()
e = 0
u = 0
}
}
return if (12 == u) {
e = e shr 4
r + e.toChar()
} else {
if (18 == u) {
e = e shr 2
r += ((65280 and e) shr 8).toChar()
r += (255 and e).toChar()
}
r
}
}
private fun encode(input: String): String? = java.net.URLEncoder.encode(input, "utf-8")
private fun decode(input: String): String? = java.net.URLDecoder.decode(input, "utf-8")
override suspend fun search(query: String): List<SearchResponse>? { override suspend fun search(query: String): List<SearchResponse>? {
val encodedquery = getVrf(query)?.let { encode(it) } ?: return null val encodedquery = encodeVrf(query, mainKey)
val url = "$mainUrl/search?keyword=$query&vrf=$encodedquery" val url = "$mainUrl/search?keyword=$query&vrf=$encodedquery"
val html = app.get(url).text val html = app.get(url).text
val document = Jsoup.parse(html) val document = Jsoup.parse(html)
@ -210,10 +108,14 @@ open class BflixProvider : MainAPI() {
@JsonProperty("html") val html: String @JsonProperty("html") val html: String
) )
companion object {
val mainKey = "OrAimkpzm6phmN3j"
}
override suspend fun load(url: String): LoadResponse? { override suspend fun load(url: String): LoadResponse? {
val soup = app.get(url).document val soup = app.get(url).document
val movieid = soup.selectFirst("div#watch")!!.attr("data-id") val movieid = soup.selectFirst("div#watch")!!.attr("data-id")
val movieidencoded = encode(getVrf(movieid) ?: return null) val movieidencoded = encodeVrf(movieid, mainKey)
val title = soup.selectFirst("div.info h1")!!.text() val title = soup.selectFirst("div.info h1")!!.text()
val description = soup.selectFirst(".info .desc")?.text()?.trim() val description = soup.selectFirst(".info .desc")?.text()?.trim()
val poster: String? = try { val poster: String? = try {
@ -223,9 +125,11 @@ open class BflixProvider : MainAPI() {
} }
val tags = soup.select("div.info .meta div:contains(Genre) a").map { it.text() } val tags = soup.select("div.info .meta div:contains(Genre) a").map { it.text() }
val vrfUrl = "$mainUrl/ajax/film/servers?id=$movieid&vrf=$movieidencoded"
println("VRF___ $vrfUrl")
val episodes = Jsoup.parse( val episodes = Jsoup.parse(
app.get( app.get(
"$mainUrl/ajax/film/servers?id=$movieid&vrf=$movieidencoded" vrfUrl
).parsed<Response>().html ).parsed<Response>().html
).select("div.episode").map { ).select("div.episode").map {
val a = it.selectFirst("a") val a = it.selectFirst("a")
@ -251,7 +155,7 @@ open class BflixProvider : MainAPI() {
if (url.contains("/movie/") && episodes.size == 1) TvType.Movie else TvType.TvSeries if (url.contains("/movie/") && episodes.size == 1) TvType.Movie else TvType.TvSeries
val recommendations = val recommendations =
soup.select("div.bl-2 section.bl div.content div.filmlist div.item") soup.select("div.bl-2 section.bl div.content div.filmlist div.item")
?.mapNotNull { element -> .mapNotNull { element ->
val recTitle = element.select("h3 a").text() ?: return@mapNotNull null val recTitle = element.select("h3 a").text() ?: return@mapNotNull null
val image = element.select("a.poster img")?.attr("src") val image = element.select("a.poster img")?.attr("src")
val recUrl = fixUrl(element.select("a").attr("href")) val recUrl = fixUrl(element.select("a").attr("href"))
@ -267,13 +171,13 @@ open class BflixProvider : MainAPI() {
val rating = soup.selectFirst(".info span.imdb")?.text()?.toRatingInt() val rating = soup.selectFirst(".info span.imdb")?.text()?.toRatingInt()
val durationdoc = soup.selectFirst("div.info div.meta").toString() val durationdoc = soup.selectFirst("div.info div.meta").toString()
val durationregex = Regex("((\\d+) min)") val durationregex = Regex("((\\d+) min)")
val yearegex = Regex("<span>(\\d+)<\\/span>") val yearegex = Regex("<span>(\\d+)</span>")
val duration = if (durationdoc.contains("na min")) null val duration = if (durationdoc.contains("na min")) null
else durationregex.find(durationdoc)?.destructured?.component1()?.replace(" min", "") else durationregex.find(durationdoc)?.destructured?.component1()?.replace(" min", "")
?.toIntOrNull() ?.toIntOrNull()
val year = if (mainUrl == "https://bflix.ru") { val year = if (mainUrl == "https://bflix.ru") {
yearegex.find(durationdoc)?.destructured?.component1() yearegex.find(durationdoc)?.destructured?.component1()
?.replace(Regex("<span>|<\\/span>"), "") ?.replace(Regex("<span>|</span>"), "")
} else null } else null
return when (tvType) { return when (tvType) {
TvType.TvSeries -> { TvType.TvSeries -> {
@ -341,7 +245,7 @@ open class BflixProvider : MainAPI() {
val soup = app.get(data).document val soup = app.get(data).document
val movieid = encode(soup.selectFirst("div#watch")?.attr("data-id") ?: return false) val movieid = encode(soup.selectFirst("div#watch")?.attr("data-id") ?: return false)
val movieidencoded = encode(getVrf(movieid!!) ?: return false) val movieidencoded = encodeVrf(movieid, mainKey)
Jsoup.parse( Jsoup.parse(
parseJson<Response>( parseJson<Response>(
app.get( app.get(
@ -372,8 +276,9 @@ open class BflixProvider : MainAPI() {
val epserver = app.get("$mainUrl/ajax/episode/info?id=$it").text val epserver = app.get("$mainUrl/ajax/episode/info?id=$it").text
(if (epserver.contains("url")) { (if (epserver.contains("url")) {
parseJson<Links>(epserver) parseJson<Links>(epserver)
} else null)?.url?.let { it1 -> getLink(it1.replace("=", "")) } } else null)?.url?.let {
?.replace("/embed/", "/e/")?.replace(Regex("(\\?sub.info.*)"), "") decodeVrf(it, mainKey)
}
}.apmap { url -> }.apmap { url ->
loadExtractor( loadExtractor(
url, data, subtitleCallback, callback url, data, subtitleCallback, callback

View file

@ -22,7 +22,7 @@ import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvicto
import com.google.android.exoplayer2.upstream.cache.SimpleCache import com.google.android.exoplayer2.upstream.cache.SimpleCache
import com.google.android.exoplayer2.util.MimeTypes import com.google.android.exoplayer2.util.MimeTypes
import com.google.android.exoplayer2.video.VideoSize import com.google.android.exoplayer2.video.VideoSize
import com.lagradost.cloudstream3.APIHolder.getApiFromName import com.lagradost.cloudstream3.APIHolder.getApiFromNameNull
import com.lagradost.cloudstream3.USER_AGENT import com.lagradost.cloudstream3.USER_AGENT
import com.lagradost.cloudstream3.app import com.lagradost.cloudstream3.app
import com.lagradost.cloudstream3.mvvm.logError import com.lagradost.cloudstream3.mvvm.logError
@ -210,6 +210,7 @@ class CS3IPlayer : IPlayer {
} }
var currentSubtitles: SubtitleData? = null var currentSubtitles: SubtitleData? = null
/** /**
* @return True if the player should be reloaded * @return True if the player should be reloaded
* */ * */
@ -353,8 +354,8 @@ class CS3IPlayer : IPlayer {
var requestSubtitleUpdate: (() -> Unit)? = null var requestSubtitleUpdate: (() -> Unit)? = null
private fun createOnlineSource(link: ExtractorLink): DataSource.Factory { private fun createOnlineSource(link: ExtractorLink): DataSource.Factory {
val provider = getApiFromName(link.source) val provider = getApiFromNameNull(link.source)
val interceptor = provider.getVideoInterceptor(link) val interceptor = provider?.getVideoInterceptor(link)
val source = if (interceptor == null) { val source = if (interceptor == null) {
DefaultHttpDataSource.Factory() //TODO USE app.baseClient DefaultHttpDataSource.Factory() //TODO USE app.baseClient

View file

@ -149,18 +149,14 @@ class SettingsLang : PreferenceFragmentCompat() {
getPref(R.string.provider_lang_key)?.setOnPreferenceClickListener { getPref(R.string.provider_lang_key)?.setOnPreferenceClickListener {
activity?.getApiProviderLangSettings()?.let { current -> activity?.getApiProviderLangSettings()?.let { current ->
var allLangs: MutableSet<String> = mutableSetOf() val langs = APIHolder.apis.map { it.lang }.toSet().sortedBy { SubtitleHelper.fromTwoLettersToLanguage(it) }
for (api in APIHolder.apis) {
allLangs.add(api.lang)
}
allLangs = allLangs.sortedBy { SubtitleHelper.fromTwoLettersToLanguage(it) }.toMutableSet()
val currentList = ArrayList<Int>() val currentList = ArrayList<Int>()
for (i in current) { for (i in current) {
currentList.add(allLangs.indexOf(i)) currentList.add(langs.indexOf(i))
} }
val names = allLangs.map { val names = langs.map {
val emoji = SubtitleHelper.getFlagFromIso(it) val emoji = SubtitleHelper.getFlagFromIso(it)
val name = SubtitleHelper.fromTwoLettersToLanguage(it) val name = SubtitleHelper.fromTwoLettersToLanguage(it)
val fullName = "$emoji $name" val fullName = "$emoji $name"

View file

@ -202,6 +202,7 @@ val extractorApis: Array<ExtractorApi> = arrayOf(
MwvnVizcloudInfo(), MwvnVizcloudInfo(),
VizcloudDigital(), VizcloudDigital(),
VizcloudCloud(), VizcloudCloud(),
VizcloudSite(),
VideoVard(), VideoVard(),
VideovardSX(), VideovardSX(),
Mp4Upload(), Mp4Upload(),