mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
small fix
This commit is contained in:
parent
4ac7e0c967
commit
cd569b44c8
7 changed files with 102 additions and 367 deletions
|
@ -17,6 +17,8 @@ class NineAnimeProvider : MainAPI() {
|
|||
override val supportedTypes = setOf(TvType.Anime)
|
||||
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 {
|
||||
fun getDubStatus(title: String): DubStatus {
|
||||
return if (title.contains("(dub)", ignoreCase = true)) {
|
||||
|
@ -31,17 +33,17 @@ class NineAnimeProvider : MainAPI() {
|
|||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||
private const val cipherKey = "rTKp3auwu0ULA6II"
|
||||
|
||||
private fun encodeVrf(text: String): String {
|
||||
fun encodeVrf(text: String, mainKey: String): String {
|
||||
return encode(
|
||||
encrypt(
|
||||
cipher(cipherKey, encode(text)),
|
||||
cipher(mainKey, encode(text)),
|
||||
nineAnimeKey
|
||||
).replace("""=+$""".toRegex(), "")
|
||||
)
|
||||
}
|
||||
|
||||
private fun decodeVrf(text: String): String {
|
||||
return decode(cipher(cipherKey, decrypt(text, nineAnimeKey)))
|
||||
fun decodeVrf(text: String, mainKey: String): String {
|
||||
return decode(cipher(mainKey, decrypt(text, nineAnimeKey)))
|
||||
}
|
||||
|
||||
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")
|
||||
|
||||
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>? {
|
||||
val vrf = encodeVrf(query)
|
||||
val vrf = encodeVrf(query, cipherKey)
|
||||
val url =
|
||||
"$mainUrl/ajax/anime/search?keyword=$query&vrf=$vrf"
|
||||
val response = app.get(url).parsedSafe<QuickSearchResponse>()
|
||||
|
@ -207,7 +209,7 @@ class NineAnimeProvider : MainAPI() {
|
|||
}
|
||||
|
||||
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"}&
|
||||
val url =
|
||||
"$mainUrl/filter?keyword=${encode(query)}&vrf=${vrf}&page=1"
|
||||
|
@ -236,7 +238,8 @@ class NineAnimeProvider : MainAPI() {
|
|||
?: throw ErrorLoadingException("Could not find title")
|
||||
|
||||
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 dubEpisodes = ArrayList<Episode>()
|
||||
|
@ -253,7 +256,7 @@ class NineAnimeProvider : MainAPI() {
|
|||
ids.getOrNull(1)?.let { dub ->
|
||||
dubEpisodes.add(
|
||||
Episode(
|
||||
"$mainUrl/ajax/server/list/$dub?vrf=${encodeVrf(dub)}",
|
||||
"$mainUrl/ajax/server/list/$dub?vrf=${encodeVrf(dub, cipherKey)}",
|
||||
epTitle,
|
||||
episode = epNum
|
||||
)
|
||||
|
@ -262,7 +265,7 @@ class NineAnimeProvider : MainAPI() {
|
|||
ids.getOrNull(0)?.let { sub ->
|
||||
subEpisodes.add(
|
||||
Episode(
|
||||
"$mainUrl/ajax/server/list/$sub?vrf=${encodeVrf(sub)}",
|
||||
"$mainUrl/ajax/server/list/$sub?vrf=${encodeVrf(sub, cipherKey)}",
|
||||
epTitle,
|
||||
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":[]}
|
||||
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(
|
||||
|
@ -338,7 +341,7 @@ class NineAnimeProvider : MainAPI() {
|
|||
val name = it.text()
|
||||
val encodedStreamUrl =
|
||||
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)) {
|
||||
callback(
|
||||
ExtractorLink(
|
||||
|
|
|
@ -1,82 +1,7 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
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() {
|
||||
open class Mcloud : WcoStream() {
|
||||
override var name = "Mcloud"
|
||||
override var mainUrl = "https://mcloud.to"
|
||||
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
|
||||
}
|
||||
}
|
|
@ -1,15 +1,13 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
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.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.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8
|
||||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
|
||||
class Vidstreamz : WcoStream() {
|
||||
override var mainUrl = "https://vidstreamz.online"
|
||||
|
@ -51,173 +49,79 @@ class VizcloudCloud : WcoStream() {
|
|||
override var mainUrl = "https://vizcloud.cloud"
|
||||
}
|
||||
|
||||
class VizcloudSite : WcoStream() {
|
||||
override var mainUrl = "https://vizcloud.site"
|
||||
}
|
||||
|
||||
open class WcoStream : ExtractorApi() {
|
||||
override var name = "VidStream" // Cause works for animekisa and wco
|
||||
override var mainUrl = "https://vidstream.pro"
|
||||
override val requiresReferer = false
|
||||
private val regex = Regex("(.+?/)e(?:mbed)?/([a-zA-Z0-9]+)")
|
||||
|
||||
companion object {
|
||||
var keytwo = ""
|
||||
fun encrypt(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
|
||||
// taken from https://github.com/saikou-app/saikou/blob/b35364c8c2a00364178a472fccf1ab72f09815b4/app/src/main/java/ani/saikou/parsers/anime/extractors/VizCloud.kt
|
||||
// GNU General Public License v3.0 https://github.com/saikou-app/saikou/blob/main/LICENSE.md
|
||||
private var lastChecked = 0L
|
||||
private const val jsonLink =
|
||||
"https://raw.githubusercontent.com/chenkaslowankiya/BruhFlow/main/keys.json"
|
||||
private var cipherKey: VizCloudKey? = null
|
||||
suspend fun getKey(): VizCloudKey {
|
||||
cipherKey =
|
||||
if (cipherKey != null && (lastChecked - System.currentTimeMillis()) < 1000 * 60 * 30) cipherKey!!
|
||||
else {
|
||||
lastChecked = System.currentTimeMillis()
|
||||
app.get(jsonLink).parsed()
|
||||
}
|
||||
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 += keytwo[n]
|
||||
}
|
||||
}
|
||||
}
|
||||
return output;
|
||||
return cipherKey!!
|
||||
}
|
||||
|
||||
fun cipher(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
|
||||
data class VizCloudKey(
|
||||
@JsonProperty("cipherKey") val cipherKey: String,
|
||||
@JsonProperty("mainKey") val mainKey: String,
|
||||
@JsonProperty("encryptKey") val encryptKey: String,
|
||||
@JsonProperty("dashTable") val dashTable: String
|
||||
)
|
||||
|
||||
private const val baseTable =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+=/_"
|
||||
|
||||
private fun dashify(id: String, dashTable: String): String {
|
||||
val table = dashTable.split(" ")
|
||||
return id.mapIndexedNotNull { i, c ->
|
||||
table.getOrNull((baseTable.indexOf(c) * 16) + (i % 16))
|
||||
}.joinToString("-")
|
||||
}
|
||||
}
|
||||
private val key = "LCbu3iYC7ln24K7P" // key credits @Modder4869
|
||||
|
||||
//private val key = "LCbu3iYC7ln24K7P" // key credits @Modder4869
|
||||
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(
|
||||
url
|
||||
)?.destructured) ?: return emptyList()
|
||||
// val (skey) = Regex("""skey\s=\s['"](.*?)['"];""").find(html)?.destructured
|
||||
// ?: return emptyList()
|
||||
val keys = getNewWcoKey()
|
||||
keytwo = keys?.encryptKey ?: return emptyList()
|
||||
val encryptedID = encrypt(cipher(keys.cipherkey!!, encrypt(Id))).replace("/", "_").replace("=","")
|
||||
val apiLink = "$baseUrl/mediainfo/$encryptedID?key=${keys.mainKey}"
|
||||
val referrer = "$baseUrl/e/$Id?domain=wcostream.cc"
|
||||
val host = group[1]
|
||||
val viz = getKey()
|
||||
val id = encrypt(
|
||||
cipher(
|
||||
viz.cipherKey,
|
||||
encrypt(group[2], viz.encryptKey).also { println(it) }
|
||||
).also { println(it) },
|
||||
viz.encryptKey
|
||||
).also { println(it) }
|
||||
|
||||
data class SourcesWco (
|
||||
@JsonProperty("file" ) val file : String
|
||||
)
|
||||
val link =
|
||||
"${host}mediainfo/${dashify(id, viz.dashTable)}?key=${viz.mainKey}" //
|
||||
val response = app.get(link, referer = referer)
|
||||
|
||||
data class MediaWco (
|
||||
@JsonProperty("sources" ) val sources : ArrayList<SourcesWco> = arrayListOf()
|
||||
)
|
||||
data class Sources(@JsonProperty("file") val file: String)
|
||||
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 (
|
||||
@JsonProperty("status" ) val status : Int? = null,
|
||||
@JsonProperty("data" ) val data : DataWco? = DataWco()
|
||||
)
|
||||
|
||||
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
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
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")
|
||||
return response.parsed<Response>().data.media.sources.map {
|
||||
ExtractorLink(name, it.file,it.file,host,Qualities.Unknown.value,it.file.contains(".m3u8"))
|
||||
}
|
||||
return sources
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,9 @@ package com.lagradost.cloudstream3.movieproviders
|
|||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
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.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
|
@ -62,113 +65,8 @@ open class BflixProvider : MainAPI() {
|
|||
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>? {
|
||||
val encodedquery = getVrf(query)?.let { encode(it) } ?: return null
|
||||
val encodedquery = encodeVrf(query, mainKey)
|
||||
val url = "$mainUrl/search?keyword=$query&vrf=$encodedquery"
|
||||
val html = app.get(url).text
|
||||
val document = Jsoup.parse(html)
|
||||
|
@ -210,10 +108,14 @@ open class BflixProvider : MainAPI() {
|
|||
@JsonProperty("html") val html: String
|
||||
)
|
||||
|
||||
companion object {
|
||||
val mainKey = "OrAimkpzm6phmN3j"
|
||||
}
|
||||
|
||||
override suspend fun load(url: String): LoadResponse? {
|
||||
val soup = app.get(url).document
|
||||
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 description = soup.selectFirst(".info .desc")?.text()?.trim()
|
||||
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 vrfUrl = "$mainUrl/ajax/film/servers?id=$movieid&vrf=$movieidencoded"
|
||||
println("VRF___ $vrfUrl")
|
||||
val episodes = Jsoup.parse(
|
||||
app.get(
|
||||
"$mainUrl/ajax/film/servers?id=$movieid&vrf=$movieidencoded"
|
||||
vrfUrl
|
||||
).parsed<Response>().html
|
||||
).select("div.episode").map {
|
||||
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
|
||||
val recommendations =
|
||||
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 image = element.select("a.poster img")?.attr("src")
|
||||
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 durationdoc = soup.selectFirst("div.info div.meta").toString()
|
||||
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
|
||||
else durationregex.find(durationdoc)?.destructured?.component1()?.replace(" min", "")
|
||||
?.toIntOrNull()
|
||||
val year = if (mainUrl == "https://bflix.ru") {
|
||||
yearegex.find(durationdoc)?.destructured?.component1()
|
||||
?.replace(Regex("<span>|<\\/span>"), "")
|
||||
?.replace(Regex("<span>|</span>"), "")
|
||||
} else null
|
||||
return when (tvType) {
|
||||
TvType.TvSeries -> {
|
||||
|
@ -341,7 +245,7 @@ open class BflixProvider : MainAPI() {
|
|||
val soup = app.get(data).document
|
||||
|
||||
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(
|
||||
parseJson<Response>(
|
||||
app.get(
|
||||
|
@ -372,8 +276,9 @@ open class BflixProvider : MainAPI() {
|
|||
val epserver = app.get("$mainUrl/ajax/episode/info?id=$it").text
|
||||
(if (epserver.contains("url")) {
|
||||
parseJson<Links>(epserver)
|
||||
} else null)?.url?.let { it1 -> getLink(it1.replace("=", "")) }
|
||||
?.replace("/embed/", "/e/")?.replace(Regex("(\\?sub.info.*)"), "")
|
||||
} else null)?.url?.let {
|
||||
decodeVrf(it, mainKey)
|
||||
}
|
||||
}.apmap { url ->
|
||||
loadExtractor(
|
||||
url, data, subtitleCallback, callback
|
||||
|
|
|
@ -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.util.MimeTypes
|
||||
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.app
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
|
@ -210,6 +210,7 @@ class CS3IPlayer : IPlayer {
|
|||
}
|
||||
|
||||
var currentSubtitles: SubtitleData? = null
|
||||
|
||||
/**
|
||||
* @return True if the player should be reloaded
|
||||
* */
|
||||
|
@ -353,8 +354,8 @@ class CS3IPlayer : IPlayer {
|
|||
var requestSubtitleUpdate: (() -> Unit)? = null
|
||||
|
||||
private fun createOnlineSource(link: ExtractorLink): DataSource.Factory {
|
||||
val provider = getApiFromName(link.source)
|
||||
val interceptor = provider.getVideoInterceptor(link)
|
||||
val provider = getApiFromNameNull(link.source)
|
||||
val interceptor = provider?.getVideoInterceptor(link)
|
||||
|
||||
val source = if (interceptor == null) {
|
||||
DefaultHttpDataSource.Factory() //TODO USE app.baseClient
|
||||
|
|
|
@ -149,18 +149,14 @@ class SettingsLang : PreferenceFragmentCompat() {
|
|||
|
||||
getPref(R.string.provider_lang_key)?.setOnPreferenceClickListener {
|
||||
activity?.getApiProviderLangSettings()?.let { current ->
|
||||
var allLangs: MutableSet<String> = mutableSetOf()
|
||||
for (api in APIHolder.apis) {
|
||||
allLangs.add(api.lang)
|
||||
}
|
||||
allLangs = allLangs.sortedBy { SubtitleHelper.fromTwoLettersToLanguage(it) }.toMutableSet()
|
||||
val langs = APIHolder.apis.map { it.lang }.toSet().sortedBy { SubtitleHelper.fromTwoLettersToLanguage(it) }
|
||||
|
||||
val currentList = ArrayList<Int>()
|
||||
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 name = SubtitleHelper.fromTwoLettersToLanguage(it)
|
||||
val fullName = "$emoji $name"
|
||||
|
|
|
@ -202,6 +202,7 @@ val extractorApis: Array<ExtractorApi> = arrayOf(
|
|||
MwvnVizcloudInfo(),
|
||||
VizcloudDigital(),
|
||||
VizcloudCloud(),
|
||||
VizcloudSite(),
|
||||
VideoVard(),
|
||||
VideovardSX(),
|
||||
Mp4Upload(),
|
||||
|
|
Loading…
Reference in a new issue