Fix Voe Extractor (#1667)

* Minor Fix for VidStack

* Fix Voe Extractor
This commit is contained in:
Phisher98
2025-04-22 00:38:40 +05:30
committed by GitHub
parent 1ffc8dd147
commit 00aa63682a

View File

@ -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()
}