mirror of
https://github.com/recloudstream/cloudstream.git
synced 2025-08-24 03:07:23 +08:00
@ -1,13 +1,16 @@
|
||||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.google.gson.JsonObject
|
||||
import com.google.gson.JsonParser
|
||||
import com.lagradost.cloudstream3.SubtitleFile
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.base64Decode
|
||||
import com.lagradost.cloudstream3.utils.AppUtils
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.INFER_TYPE
|
||||
import com.lagradost.cloudstream3.utils.M3u8Helper
|
||||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
import com.lagradost.cloudstream3.utils.newExtractorLink
|
||||
|
||||
class Tubeless : Voe() {
|
||||
override val name = "Tubeless"
|
||||
@ -46,11 +49,8 @@ open class Voe : ExtractorApi() {
|
||||
override val name = "Voe"
|
||||
override val mainUrl = "https://voe.sx"
|
||||
override val requiresReferer = true
|
||||
|
||||
private val linkRegex =
|
||||
"(http|https)://([\\w_-]+(?:\\.[\\w_-]+)+)([\\w.,@?^=%&:/~+#-]*[\\w@?^=%&/~+#-])".toRegex()
|
||||
private val base64Regex = Regex("'.*'")
|
||||
private val redirectRegex = Regex("""window.location.href = '([^']+)';""")
|
||||
private val redirectRegex = Regex("""window.location.href\s*=\s*'([^']+)';""")
|
||||
private val encodedRegex = Regex("""MKGMa="(.*?)";""", RegexOption.DOT_MATCHES_ALL)
|
||||
|
||||
override suspend fun getUrl(
|
||||
url: String,
|
||||
@ -58,52 +58,84 @@ open class Voe : ExtractorApi() {
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
) {
|
||||
val res = app.get(url, referer = referer).document
|
||||
|
||||
val script =
|
||||
if (!res.select("script").firstOrNull() { it.data().contains("sources =") }?.data()
|
||||
.isNullOrEmpty()
|
||||
) {
|
||||
res.select("script").find { it.data().contains("sources =") }?.data()
|
||||
} else {
|
||||
redirectRegex.find(res.data())?.groupValues?.get(1)?.let { redirectUrl ->
|
||||
app.get(
|
||||
redirectUrl,
|
||||
referer = referer
|
||||
).document.select("script").find { it.data().contains("sources =") }?.data()
|
||||
}
|
||||
}
|
||||
|
||||
val link =
|
||||
Regex("[\"']hls[\"']:\\s*[\"'](.*)[\"']").find(script ?: return)?.groupValues?.get(1)
|
||||
|
||||
val videoLinks = mutableListOf<String>()
|
||||
|
||||
if (!link.isNullOrBlank()) {
|
||||
videoLinks.add(
|
||||
when {
|
||||
linkRegex.matches(link) -> link
|
||||
else -> base64Decode(link)
|
||||
}
|
||||
)
|
||||
} else {
|
||||
val link2 = base64Regex.find(script)?.value ?: return
|
||||
val decoded = base64Decode(link2)
|
||||
val videoLinkDTO = AppUtils.parseJson<WcoSources>(decoded)
|
||||
videoLinkDTO.let { videoLinks.add(it.toString()) }
|
||||
var res = app.get(url, referer = referer)
|
||||
val redirectUrl = redirectRegex.find(res.document.data())?.groupValues?.get(1)
|
||||
if (redirectUrl != null) {
|
||||
res = app.get(redirectUrl, referer = referer)
|
||||
}
|
||||
val encodedString = encodedRegex.find(res.body.string())?.groupValues?.get(1)
|
||||
if (encodedString == null) {
|
||||
println("MKGMa string not found.")
|
||||
return
|
||||
}
|
||||
val decryptedJson = decryptF7(encodedString)
|
||||
val m3u8 = decryptedJson.get("source")?.asString
|
||||
val mp4 = decryptedJson.get("direct_access_url")?.asString
|
||||
|
||||
videoLinks.forEach { videoLink ->
|
||||
if (m3u8 != null) {
|
||||
M3u8Helper.generateM3u8(
|
||||
name,
|
||||
videoLink,
|
||||
m3u8,
|
||||
"$mainUrl/",
|
||||
headers = mapOf("Origin" to "$mainUrl/")
|
||||
).forEach(callback)
|
||||
}
|
||||
if (mp4!=null)
|
||||
{
|
||||
callback.invoke(
|
||||
newExtractorLink(
|
||||
source = "$name MP4",
|
||||
name = "$name MP4",
|
||||
url = mp4,
|
||||
INFER_TYPE
|
||||
) {
|
||||
this.referer = url
|
||||
this.quality = Qualities.Unknown.value
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
data class WcoSources(
|
||||
@JsonProperty("VideoLinkDTO") val VideoLinkDTO: String,
|
||||
)
|
||||
private fun decryptF7(p8: String): JsonObject {
|
||||
return try {
|
||||
val vF = rot13(p8)
|
||||
val vF2 = replacePatterns(vF)
|
||||
val vF3 = removeUnderscores(vF2)
|
||||
val vF4 = base64Decode(vF3)
|
||||
val vF5 = charShift(vF4, 3)
|
||||
val vF6 = reverse(vF5)
|
||||
val vAtob = base64Decode(vF6)
|
||||
|
||||
JsonParser.parseString(vAtob).asJsonObject
|
||||
} catch (e: Exception) {
|
||||
println("Decryption error: ${e.message}")
|
||||
JsonObject()
|
||||
}
|
||||
}
|
||||
|
||||
private fun rot13(input: String): String {
|
||||
return input.map { c ->
|
||||
when (c) {
|
||||
in 'A'..'Z' -> ((c - 'A' + 13) % 26 + 'A'.code).toChar()
|
||||
in 'a'..'z' -> ((c - 'a' + 13) % 26 + 'a'.code).toChar()
|
||||
else -> c
|
||||
}
|
||||
}.joinToString("")
|
||||
}
|
||||
|
||||
private fun replacePatterns(input: String): String {
|
||||
val patterns = listOf("@$", "^^", "~@", "%?", "*~", "!!", "#&")
|
||||
return patterns.fold(input) { result, pattern ->
|
||||
result.replace(Regex(Regex.escape(pattern)), "_")
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeUnderscores(input: String): String = input.replace("_", "")
|
||||
|
||||
private fun charShift(input: String, shift: Int): String {
|
||||
return input.map { (it.code - shift).toChar() }.joinToString("")
|
||||
}
|
||||
|
||||
private fun reverse(input: String): String = input.reversed()
|
||||
|
||||
}
|
||||
|
Reference in New Issue
Block a user