mirror of
https://github.com/recloudstream/cloudstream.git
synced 2024-08-15 01:53:11 +00:00
readded extractors (remove the extractors repo)
This commit is contained in:
parent
cb11cd13e6
commit
5508c2d14e
54 changed files with 3198 additions and 36 deletions
|
@ -706,17 +706,5 @@ class MainActivity : AppCompatActivity(), ColorPickerDialogListener {
|
|||
// }
|
||||
// }
|
||||
|
||||
/*
|
||||
|
||||
val relativePath = (Environment.DIRECTORY_DOWNLOADS) + File.separatorChar
|
||||
val displayName = "output.dex" //""output.dex"
|
||||
val file = getExternalFilesDir(null)?.absolutePath + File.separatorChar + displayName//"${Environment.getExternalStorageDirectory()}${File.separatorChar}$relativePath$displayName"
|
||||
println(file)
|
||||
|
||||
val realFile = File(file)
|
||||
println("REAALFILE: ${realFile.exists()} at ${realFile.length()}" )
|
||||
val src = ExtensionManager.getSourceFromDex(this, "com.example.testdex2.TestClassToDex", File(file))
|
||||
val output = src?.doMath()
|
||||
println("MASTER OUTPUT = $output")*/
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.base64Decode
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
|
||||
class Acefile : ExtractorApi() {
|
||||
override val name = "Acefile"
|
||||
override val mainUrl = "https://acefile.co"
|
||||
override val requiresReferer = false
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
|
||||
val sources = mutableListOf<ExtractorLink>()
|
||||
app.get(url).document.select("script").map { script ->
|
||||
if (script.data().contains("eval(function(p,a,c,k,e,d)")) {
|
||||
val data = getAndUnpack(script.data())
|
||||
val id = data.substringAfter("{\"id\":\"").substringBefore("\",")
|
||||
val key = data.substringAfter("var nfck=\"").substringBefore("\";")
|
||||
app.get("https://acefile.co/local/$id?key=$key").text.let {
|
||||
base64Decode(
|
||||
it.substringAfter("JSON.parse(atob(\"").substringBefore("\"))")
|
||||
).let { res ->
|
||||
sources.add(
|
||||
ExtractorLink(
|
||||
name,
|
||||
name,
|
||||
res.substringAfter("\"file\":\"").substringBefore("\","),
|
||||
"$mainUrl/",
|
||||
Qualities.Unknown.value,
|
||||
headers = mapOf("range" to "bytes=0-")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return sources
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.M3u8Helper
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
import java.net.URI
|
||||
|
||||
class AsianLoad : ExtractorApi() {
|
||||
override var name = "AsianLoad"
|
||||
override var mainUrl = "https://asianembed.io"
|
||||
override val requiresReferer = true
|
||||
|
||||
private val sourceRegex = Regex("""sources:[\W\w]*?file:\s*?["'](.*?)["']""")
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
|
||||
val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
|
||||
with(app.get(url, referer = referer)) {
|
||||
sourceRegex.findAll(this.text).forEach { sourceMatch ->
|
||||
val extractedUrl = sourceMatch.groupValues[1]
|
||||
// Trusting this isn't mp4, may fuck up stuff
|
||||
if (URI(extractedUrl).path.endsWith(".m3u8")) {
|
||||
M3u8Helper.generateM3u8(
|
||||
name,
|
||||
extractedUrl,
|
||||
url,
|
||||
headers = mapOf("referer" to this.url)
|
||||
).forEach { link ->
|
||||
extractedLinksList.add(link)
|
||||
}
|
||||
} else if (extractedUrl.endsWith(".mp4")) {
|
||||
extractedLinksList.add(
|
||||
ExtractorLink(
|
||||
name,
|
||||
name,
|
||||
extractedUrl,
|
||||
url.replace(" ", "%20"),
|
||||
getQualityFromName(sourceMatch.groupValues[2]),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
return extractedLinksList
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
||||
|
||||
class Blogger : ExtractorApi() {
|
||||
override val name = "Blogger"
|
||||
override val mainUrl = "https://www.blogger.com"
|
||||
override val requiresReferer = false
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
|
||||
val sources = mutableListOf<ExtractorLink>()
|
||||
with(app.get(url).document) {
|
||||
this.select("script").map { script ->
|
||||
if (script.data().contains("\"streams\":[")) {
|
||||
val data = script.data().substringAfter("\"streams\":[")
|
||||
.substringBefore("]")
|
||||
tryParseJson<List<ResponseSource>>("[$data]")?.map {
|
||||
sources.add(
|
||||
ExtractorLink(
|
||||
name,
|
||||
name,
|
||||
it.play_url,
|
||||
referer = "https://www.youtube.com/",
|
||||
quality = when (it.format_id) {
|
||||
18 -> 360
|
||||
22 -> 720
|
||||
else -> Qualities.Unknown.value
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return sources
|
||||
}
|
||||
|
||||
private data class ResponseSource(
|
||||
@JsonProperty("play_url") val play_url: String,
|
||||
@JsonProperty("format_id") val format_id: Int
|
||||
)
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.M3u8Helper
|
||||
|
||||
class BullStream : ExtractorApi() {
|
||||
override val name = "BullStream"
|
||||
override val mainUrl = "https://bullstream.xyz"
|
||||
override val requiresReferer = false
|
||||
val regex = Regex("(?<=sniff\\()(.*)(?=\\)\\);)")
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||
val data = regex.find(app.get(url).text)?.value
|
||||
?.replace("\"", "")
|
||||
?.split(",")
|
||||
?: return null
|
||||
|
||||
val m3u8 = "$mainUrl/m3u8/${data[1]}/${data[2]}/master.txt?s=1&cache=${data[4]}"
|
||||
println("shiv : $m3u8")
|
||||
return M3u8Helper.generateM3u8(
|
||||
name,
|
||||
m3u8,
|
||||
url,
|
||||
headers = mapOf("referer" to url, "accept" to "*/*")
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
import kotlinx.coroutines.delay
|
||||
|
||||
class DoodCxExtractor : DoodLaExtractor() {
|
||||
override var mainUrl = "https://dood.cx"
|
||||
}
|
||||
|
||||
class DoodShExtractor : DoodLaExtractor() {
|
||||
override var mainUrl = "https://dood.sh"
|
||||
}
|
||||
class DoodWatchExtractor : DoodLaExtractor() {
|
||||
override var mainUrl = "https://dood.watch"
|
||||
}
|
||||
|
||||
class DoodPmExtractor : DoodLaExtractor() {
|
||||
override var mainUrl = "https://dood.pm"
|
||||
}
|
||||
|
||||
class DoodToExtractor : DoodLaExtractor() {
|
||||
override var mainUrl = "https://dood.to"
|
||||
}
|
||||
|
||||
class DoodSoExtractor : DoodLaExtractor() {
|
||||
override var mainUrl = "https://dood.so"
|
||||
}
|
||||
|
||||
class DoodWsExtractor : DoodLaExtractor() {
|
||||
override var mainUrl = "https://dood.ws"
|
||||
}
|
||||
|
||||
|
||||
open class DoodLaExtractor : ExtractorApi() {
|
||||
override var name = "DoodStream"
|
||||
override var mainUrl = "https://dood.la"
|
||||
override val requiresReferer = false
|
||||
|
||||
override fun getExtractorUrl(id: String): String {
|
||||
return "$mainUrl/d/$id"
|
||||
}
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||
val response0 = app.get(url).text // html of DoodStream page to look for /pass_md5/...
|
||||
val md5 =mainUrl+(Regex("/pass_md5/[^']*").find(response0)?.value ?: return null) // get https://dood.ws/pass_md5/...
|
||||
val trueUrl = app.get(md5, referer = url).text + "zUEJeL3mUN?token=" + md5.substringAfterLast("/") //direct link to extract (zUEJeL3mUN is random)
|
||||
val quality = Regex("\\d{3,4}p").find(response0.substringAfter("<title>").substringBefore("</title>"))?.groupValues?.get(0)
|
||||
return listOf(
|
||||
ExtractorLink(
|
||||
trueUrl,
|
||||
this.name,
|
||||
trueUrl,
|
||||
mainUrl,
|
||||
getQualityFromName(quality),
|
||||
false
|
||||
)
|
||||
) // links are valid in 8h
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
import com.lagradost.cloudstream3.app
|
||||
|
||||
class Evoload1 : Evoload() {
|
||||
override var mainUrl = "https://evoload.io"
|
||||
}
|
||||
|
||||
open class Evoload : ExtractorApi() {
|
||||
override val name: String = "Evoload"
|
||||
override val mainUrl: String = "https://www.evoload.io"
|
||||
//private val srcRegex = Regex("""video .*src="(.*)""""") // would be possible to use the parse and find src attribute
|
||||
override val requiresReferer = true
|
||||
|
||||
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
|
||||
val lang = url.substring(0, 2)
|
||||
val flag =
|
||||
if (lang == "vo") {
|
||||
" \uD83C\uDDEC\uD83C\uDDE7"
|
||||
}
|
||||
else if (lang == "vf"){
|
||||
" \uD83C\uDDE8\uD83C\uDDF5"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
|
||||
val cleaned_url = if (lang == "ht") { // if url doesn't contain a flag and the url starts with http://
|
||||
url
|
||||
} else {
|
||||
url.substring(2, url.length)
|
||||
}
|
||||
//println(lang)
|
||||
//println(cleaned_url)
|
||||
|
||||
val id = cleaned_url.replace("https://evoload.io/e/", "") // wanted media id
|
||||
val csrv_token = app.get("https://csrv.evosrv.com/captcha?m412548=").text // whatever that is
|
||||
val captchaPass = app.get("https://cd2.evosrv.com/html/jsx/e.jsx").text.take(300).split("captcha_pass = '")[1].split("\'")[0] //extract the captcha pass from the js response (located in the 300 first chars)
|
||||
val payload = mapOf("code" to id, "csrv_token" to csrv_token, "pass" to captchaPass)
|
||||
val r = app.post("https://evoload.io/SecurePlayer", data=(payload)).text
|
||||
val link = Regex("src\":\"(.*?)\"").find(r)?.destructured?.component1() ?: return listOf()
|
||||
return listOf(
|
||||
ExtractorLink(
|
||||
name,
|
||||
name + flag,
|
||||
link,
|
||||
cleaned_url,
|
||||
Qualities.Unknown.value,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.apmap
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8
|
||||
|
||||
class Fastream: ExtractorApi() {
|
||||
override var mainUrl = "https://fastream.to"
|
||||
override var name = "Fastream"
|
||||
override val requiresReferer = false
|
||||
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||
val id = Regex("emb\\.html\\?(.*)\\=(enc|)").find(url)?.destructured?.component1() ?: return emptyList()
|
||||
val sources = mutableListOf<ExtractorLink>()
|
||||
val response = app.post("$mainUrl/dl",
|
||||
data = mapOf(
|
||||
Pair("op","embed"),
|
||||
Pair("file_code",id),
|
||||
Pair("auto","1")
|
||||
)).document
|
||||
response.select("script").apmap { script ->
|
||||
if (script.data().contains("sources")) {
|
||||
val m3u8regex = Regex("((https:|http:)\\/\\/.*\\.m3u8)")
|
||||
val m3u8 = m3u8regex.find(script.data())?.value ?: return@apmap
|
||||
generateM3u8(
|
||||
name,
|
||||
m3u8,
|
||||
mainUrl
|
||||
).forEach { link ->
|
||||
sources.add(link)
|
||||
}
|
||||
}
|
||||
}
|
||||
return sources
|
||||
}
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
||||
|
||||
class Filesim : ExtractorApi() {
|
||||
override val name = "Filesim"
|
||||
override val mainUrl = "https://files.im"
|
||||
override val requiresReferer = false
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
|
||||
val sources = mutableListOf<ExtractorLink>()
|
||||
with(app.get(url).document) {
|
||||
this.select("script").map { script ->
|
||||
if (script.data().contains("eval(function(p,a,c,k,e,d)")) {
|
||||
val data = getAndUnpack(script.data()).substringAfter("sources:[").substringBefore("]")
|
||||
tryParseJson<List<ResponseSource>>("[$data]")?.map {
|
||||
M3u8Helper.generateM3u8(
|
||||
name,
|
||||
it.file,
|
||||
"$mainUrl/",
|
||||
).forEach { m3uData -> sources.add(m3uData) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return sources
|
||||
}
|
||||
|
||||
private data class ResponseSource(
|
||||
@JsonProperty("file") val file: String,
|
||||
@JsonProperty("type") val type: String?,
|
||||
@JsonProperty("label") val label: String?
|
||||
)
|
||||
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.M3u8Helper
|
||||
|
||||
class GMPlayer : ExtractorApi() {
|
||||
override val name = "GM Player"
|
||||
override val mainUrl = "https://gmplayer.xyz"
|
||||
override val requiresReferer = true
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||
val ref = referer ?: return null
|
||||
val id = url.substringAfter("/video/").substringBefore("/")
|
||||
|
||||
val m3u8 = app.post(
|
||||
"$mainUrl/player/index.php?data=$id&do=getVideo",
|
||||
mapOf(
|
||||
"accept" to "*/*",
|
||||
"referer" to ref,
|
||||
"x-requested-with" to "XMLHttpRequest",
|
||||
"origin" to mainUrl
|
||||
),
|
||||
data = mapOf("hash" to id, "r" to ref)
|
||||
).parsed<GmResponse>().videoSource ?: return null
|
||||
|
||||
return M3u8Helper.generateM3u8(
|
||||
name,
|
||||
m3u8,
|
||||
ref,
|
||||
headers = mapOf("accept" to "*/*")
|
||||
)
|
||||
}
|
||||
|
||||
private data class GmResponse(
|
||||
val videoSource: String? = null
|
||||
)
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.network.WebViewResolver
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.M3u8Helper
|
||||
|
||||
|
||||
open class GenericM3U8 : ExtractorApi() {
|
||||
override var name = "Upstream"
|
||||
override var mainUrl = "https://upstream.to"
|
||||
override val requiresReferer = false
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
|
||||
val response = app.get(
|
||||
url, interceptor = WebViewResolver(
|
||||
Regex("""master\.m3u8""")
|
||||
)
|
||||
)
|
||||
val sources = mutableListOf<ExtractorLink>()
|
||||
if (response.url.contains("m3u8"))
|
||||
M3u8Helper.generateM3u8(
|
||||
name,
|
||||
response.url,
|
||||
url,
|
||||
headers = response.headers.toMap()
|
||||
).forEach { link ->
|
||||
sources.add(link)
|
||||
}
|
||||
return sources
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
|
||||
open class GuardareStream : ExtractorApi() {
|
||||
override var name = "Guardare"
|
||||
override var mainUrl = "https://guardare.stream"
|
||||
override val requiresReferer = false
|
||||
|
||||
data class GuardareJsonData (
|
||||
@JsonProperty("data") val data : List<GuardareData>,
|
||||
)
|
||||
|
||||
data class GuardareData (
|
||||
@JsonProperty("file") val file : String,
|
||||
@JsonProperty("label") val label : String,
|
||||
@JsonProperty("type") val type : String
|
||||
)
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||
val response = app.post(url.replace("/v/","/api/source/"), data = mapOf("d" to mainUrl)).text
|
||||
val jsonvideodata = AppUtils.parseJson<GuardareJsonData>(response)
|
||||
return jsonvideodata.data.map {
|
||||
ExtractorLink(
|
||||
it.file+".${it.type}",
|
||||
this.name,
|
||||
it.file+".${it.type}",
|
||||
mainUrl,
|
||||
it.label.filter{ it.isDigit() }.toInt(),
|
||||
false
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,100 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
||||
|
||||
class Neonime7n : Hxfile() {
|
||||
override val name = "Neonime7n"
|
||||
override val mainUrl = "https://7njctn.neonime.watch"
|
||||
override val redirect = false
|
||||
}
|
||||
|
||||
class Neonime8n : Hxfile() {
|
||||
override val name = "Neonime8n"
|
||||
override val mainUrl = "https://8njctn.neonime.net"
|
||||
override val redirect = false
|
||||
}
|
||||
|
||||
class KotakAnimeid : Hxfile() {
|
||||
override val name = "KotakAnimeid"
|
||||
override val mainUrl = "https://kotakanimeid.com"
|
||||
override val requiresReferer = true
|
||||
}
|
||||
|
||||
class Yufiles : Hxfile() {
|
||||
override val name = "Yufiles"
|
||||
override val mainUrl = "https://yufiles.com"
|
||||
}
|
||||
|
||||
class Aico : Hxfile() {
|
||||
override val name = "Aico"
|
||||
override val mainUrl = "https://aico.pw"
|
||||
}
|
||||
|
||||
open class Hxfile : ExtractorApi() {
|
||||
override val name = "Hxfile"
|
||||
override val mainUrl = "https://hxfile.co"
|
||||
override val requiresReferer = false
|
||||
open val redirect = true
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||
val sources = mutableListOf<ExtractorLink>()
|
||||
val document = app.get(url, allowRedirects = redirect, referer = referer).document
|
||||
with(document) {
|
||||
this.select("script").map { script ->
|
||||
if (script.data().contains("eval(function(p,a,c,k,e,d)")) {
|
||||
val data =
|
||||
getAndUnpack(script.data()).substringAfter("sources:[").substringBefore("]")
|
||||
tryParseJson<List<ResponseSource>>("[$data]")?.map {
|
||||
sources.add(
|
||||
ExtractorLink(
|
||||
name,
|
||||
name,
|
||||
it.file,
|
||||
referer = mainUrl,
|
||||
quality = when {
|
||||
url.contains("hxfile.co") -> getQualityFromName(
|
||||
Regex("\\d\\.(.*?).mp4").find(
|
||||
document.select("title").text()
|
||||
)?.groupValues?.get(1).toString()
|
||||
)
|
||||
else -> getQualityFromName(it.label)
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
} else if (script.data().contains("\"sources\":[")) {
|
||||
val data = script.data().substringAfter("\"sources\":[").substringBefore("]")
|
||||
tryParseJson<List<ResponseSource>>("[$data]")?.map {
|
||||
sources.add(
|
||||
ExtractorLink(
|
||||
name,
|
||||
name,
|
||||
it.file,
|
||||
referer = mainUrl,
|
||||
quality = when {
|
||||
it.label?.contains("HD") == true -> Qualities.P720.value
|
||||
it.label?.contains("SD") == true -> Qualities.P480.value
|
||||
else -> getQualityFromName(it.label)
|
||||
}
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
else {
|
||||
null
|
||||
}
|
||||
}
|
||||
}
|
||||
return sources
|
||||
}
|
||||
|
||||
private data class ResponseSource(
|
||||
@JsonProperty("file") val file: String,
|
||||
@JsonProperty("type") val type: String?,
|
||||
@JsonProperty("label") val label: String?
|
||||
)
|
||||
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
|
||||
class Meownime : JWPlayer() {
|
||||
override val name = "Meownime"
|
||||
override val mainUrl = "https://meownime.ltd"
|
||||
}
|
||||
|
||||
class DesuOdchan : JWPlayer() {
|
||||
override val name = "DesuOdchan"
|
||||
override val mainUrl = "https://desustream.me/odchan/"
|
||||
}
|
||||
|
||||
class DesuArcg : JWPlayer() {
|
||||
override val name = "DesuArcg"
|
||||
override val mainUrl = "https://desustream.me/arcg/"
|
||||
}
|
||||
|
||||
class DesuDrive : JWPlayer() {
|
||||
override val name = "DesuDrive"
|
||||
override val mainUrl = "https://desustream.me/desudrive/"
|
||||
}
|
||||
|
||||
class DesuOdvip : JWPlayer() {
|
||||
override val name = "DesuOdvip"
|
||||
override val mainUrl = "https://desustream.me/odvip/"
|
||||
}
|
||||
|
||||
open class JWPlayer : ExtractorApi() {
|
||||
override val name = "JWPlayer"
|
||||
override val mainUrl = "https://www.jwplayer.com"
|
||||
override val requiresReferer = false
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||
val sources = mutableListOf<ExtractorLink>()
|
||||
with(app.get(url).document) {
|
||||
val data = this.select("script").mapNotNull { script ->
|
||||
if (script.data().contains("sources: [")) {
|
||||
script.data().substringAfter("sources: [")
|
||||
.substringBefore("],").replace("'", "\"")
|
||||
} else if (script.data().contains("otakudesu('")) {
|
||||
script.data().substringAfter("otakudesu('")
|
||||
.substringBefore("');")
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
tryParseJson<List<ResponseSource>>("$data")?.map {
|
||||
sources.add(
|
||||
ExtractorLink(
|
||||
name,
|
||||
name,
|
||||
it.file,
|
||||
referer = url,
|
||||
quality = getQualityFromName(
|
||||
Regex("(\\d{3,4}p)").find(it.file)?.groupValues?.get(
|
||||
1
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
return sources
|
||||
}
|
||||
|
||||
private data class ResponseSource(
|
||||
@JsonProperty("file") val file: String,
|
||||
@JsonProperty("type") val type: String?,
|
||||
@JsonProperty("label") val label: String?
|
||||
)
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.M3u8Helper
|
||||
|
||||
|
||||
open class Jawcloud : ExtractorApi() {
|
||||
override var name = "Jawcloud"
|
||||
override var mainUrl = "https://jawcloud.co"
|
||||
override val requiresReferer = false
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||
val doc = app.get(url).document
|
||||
val urlString = doc.select("html body div source").attr("src")
|
||||
val sources = mutableListOf<ExtractorLink>()
|
||||
if (urlString.contains("m3u8"))
|
||||
M3u8Helper.generateM3u8(
|
||||
name,
|
||||
urlString,
|
||||
url,
|
||||
headers = app.get(url).headers.toMap()
|
||||
).forEach { link -> sources.add(link) }
|
||||
return sources
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
|
||||
class Linkbox : ExtractorApi() {
|
||||
override val name = "Linkbox"
|
||||
override val mainUrl = "https://www.linkbox.to"
|
||||
override val requiresReferer = true
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
|
||||
val id = url.substringAfter("id=")
|
||||
val sources = mutableListOf<ExtractorLink>()
|
||||
|
||||
app.get("$mainUrl/api/open/get_url?itemId=$id", referer=url).parsedSafe<Responses>()?.data?.rList?.map { link ->
|
||||
sources.add(
|
||||
ExtractorLink(
|
||||
name,
|
||||
name,
|
||||
link.url,
|
||||
url,
|
||||
getQualityFromName(link.resolution)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
return sources
|
||||
}
|
||||
|
||||
data class RList(
|
||||
@JsonProperty("url") val url: String,
|
||||
@JsonProperty("resolution") val resolution: String?,
|
||||
)
|
||||
|
||||
data class Data(
|
||||
@JsonProperty("rList") val rList: List<RList>?,
|
||||
)
|
||||
|
||||
data class Responses(
|
||||
@JsonProperty("data") val data: Data?,
|
||||
)
|
||||
|
||||
}
|
|
@ -0,0 +1,16 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
//{"auto":"/manifests/movies/15559/1624728920/qDwu5BOsfAwfTmnnjmkmXA/master.m3u8","1080p":"https://vdoc3.sallenes.space/qDwu5BOsfAwfTmnnjmkmXA/1624728920/storage6/movies/the-man-with-the-iron-heart-2017/1080p/index.m3u8","720p":"https://vdoc3.sallenes.space/qDwu5BOsfAwfTmnnjmkmXA/1624728920/storage6/movies/the-man-with-the-iron-heart-2017/720p/index.m3u8","360p":"https://vdoc3.sallenes.space/qDwu5BOsfAwfTmnnjmkmXA/1624728920/storage6/movies/the-man-with-the-iron-heart-2017/360p/index.m3u8","480p":"https://vdoc3.sallenes.space/qDwu5BOsfAwfTmnnjmkmXA/1624728920/storage6/movies/the-man-with-the-iron-heart-2017/480p/index.m3u8"}
|
||||
object M3u8Manifest {
|
||||
// URL = first, QUALITY = second
|
||||
fun extractLinks(m3u8Data: String): ArrayList<Pair<String, String>> {
|
||||
val data: ArrayList<Pair<String, String>> = ArrayList()
|
||||
Regex("\"(.*?)\":\"(.*?)\"").findAll(m3u8Data).forEach {
|
||||
var quality = it.groupValues[1].replace("auto", "Auto")
|
||||
if (quality != "Auto" && !quality.endsWith('p')) quality += "p"
|
||||
val url = it.groupValues[2]
|
||||
data.add(Pair(url, quality))
|
||||
}
|
||||
return data
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
|
||||
open class Maxstream : ExtractorApi() {
|
||||
override var name = "Maxstream"
|
||||
override var mainUrl = "https://maxstream.video/"
|
||||
override val requiresReferer = false
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||
val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
|
||||
val response = app.get(url).text
|
||||
val jstounpack = Regex("cript\">eval((.|\\n)*?)</script>").find(response)?.groups?.get(1)?.value
|
||||
val unpacjed = JsUnpacker(jstounpack).unpack()
|
||||
val extractedUrl = unpacjed?.let { Regex("""src:"((.|\n)*?)",type""").find(it) }?.groups?.get(1)?.value.toString()
|
||||
|
||||
M3u8Helper.generateM3u8(
|
||||
name,
|
||||
extractedUrl,
|
||||
url,
|
||||
headers = mapOf("referer" to url)
|
||||
).forEach { link ->
|
||||
extractedLinksList.add(link)
|
||||
}
|
||||
|
||||
return extractedLinksList
|
||||
}
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
open class Mcloud : WcoStream() {
|
||||
override var name = "Mcloud"
|
||||
override var mainUrl = "https://mcloud.to"
|
||||
override val requiresReferer = true
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
|
||||
class MixDropBz : MixDrop(){
|
||||
override var mainUrl = "https://mixdrop.bz"
|
||||
}
|
||||
|
||||
class MixDropCh : MixDrop(){
|
||||
override var mainUrl = "https://mixdrop.ch"
|
||||
}
|
||||
class MixDropTo : MixDrop(){
|
||||
override var mainUrl = "https://mixdrop.to"
|
||||
}
|
||||
|
||||
open class MixDrop : ExtractorApi() {
|
||||
override var name = "MixDrop"
|
||||
override var mainUrl = "https://mixdrop.co"
|
||||
private val srcRegex = Regex("""wurl.*?=.*?"(.*?)";""")
|
||||
override val requiresReferer = false
|
||||
|
||||
override fun getExtractorUrl(id: String): String {
|
||||
return "$mainUrl/e/$id"
|
||||
}
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||
with(app.get(url)) {
|
||||
getAndUnpack(this.text).let { unpackedText ->
|
||||
srcRegex.find(unpackedText)?.groupValues?.get(1)?.let { link ->
|
||||
return listOf(
|
||||
ExtractorLink(
|
||||
name,
|
||||
name,
|
||||
httpsify(link),
|
||||
url,
|
||||
Qualities.Unknown.value,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
import com.lagradost.cloudstream3.utils.getAndUnpack
|
||||
|
||||
class Mp4Upload : ExtractorApi() {
|
||||
override var name = "Mp4Upload"
|
||||
override var mainUrl = "https://www.mp4upload.com"
|
||||
private val srcRegex = Regex("""player\.src\("(.*?)"""")
|
||||
override val requiresReferer = true
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||
with(app.get(url)) {
|
||||
getAndUnpack(this.text).let { unpackedText ->
|
||||
val quality = unpackedText.lowercase().substringAfter(" height=").substringBefore(" ").toIntOrNull()
|
||||
srcRegex.find(unpackedText)?.groupValues?.get(1)?.let { link ->
|
||||
return listOf(
|
||||
ExtractorLink(
|
||||
name,
|
||||
name,
|
||||
link,
|
||||
url,
|
||||
quality ?: Qualities.Unknown.value,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
import java.net.URI
|
||||
|
||||
class MultiQuality : ExtractorApi() {
|
||||
override var name = "MultiQuality"
|
||||
override var mainUrl = "https://gogo-play.net"
|
||||
private val sourceRegex = Regex("""file:\s*['"](.*?)['"],label:\s*['"](.*?)['"]""")
|
||||
private val m3u8Regex = Regex(""".*?(\d*).m3u8""")
|
||||
private val urlRegex = Regex("""(.*?)([^/]+$)""")
|
||||
override val requiresReferer = false
|
||||
|
||||
override fun getExtractorUrl(id: String): String {
|
||||
return "$mainUrl/loadserver.php?id=$id"
|
||||
}
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
|
||||
val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
|
||||
with(app.get(url)) {
|
||||
sourceRegex.findAll(this.text).forEach { sourceMatch ->
|
||||
val extractedUrl = sourceMatch.groupValues[1]
|
||||
// Trusting this isn't mp4, may fuck up stuff
|
||||
if (URI(extractedUrl).path.endsWith(".m3u8")) {
|
||||
with(app.get(extractedUrl)) {
|
||||
m3u8Regex.findAll(this.text).forEach { match ->
|
||||
extractedLinksList.add(
|
||||
ExtractorLink(
|
||||
name,
|
||||
name = name,
|
||||
urlRegex.find(this.url)!!.groupValues[1] + match.groupValues[0],
|
||||
url,
|
||||
getQualityFromName(match.groupValues[1]),
|
||||
isM3u8 = true
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
}
|
||||
} else if (extractedUrl.endsWith(".mp4")) {
|
||||
extractedLinksList.add(
|
||||
ExtractorLink(
|
||||
name,
|
||||
"$name ${sourceMatch.groupValues[2]}",
|
||||
extractedUrl,
|
||||
url.replace(" ", "%20"),
|
||||
Qualities.Unknown.value,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
return extractedLinksList
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,67 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
||||
|
||||
data class DataOptionsJson (
|
||||
@JsonProperty("flashvars") var flashvars : Flashvars? = Flashvars(),
|
||||
)
|
||||
data class Flashvars (
|
||||
@JsonProperty("metadata") var metadata : String? = null,
|
||||
@JsonProperty("hlsManifestUrl") var hlsManifestUrl : String? = null, //m3u8
|
||||
)
|
||||
|
||||
data class MetadataOkru (
|
||||
@JsonProperty("videos") var videos: ArrayList<Videos> = arrayListOf(),
|
||||
)
|
||||
|
||||
data class Videos (
|
||||
@JsonProperty("name") var name : String,
|
||||
@JsonProperty("url") var url : String,
|
||||
@JsonProperty("seekSchema") var seekSchema : Int? = null,
|
||||
@JsonProperty("disallowed") var disallowed : Boolean? = null
|
||||
)
|
||||
|
||||
class OkRuHttps: OkRu(){
|
||||
override var mainUrl = "https://ok.ru"
|
||||
}
|
||||
|
||||
open class OkRu : ExtractorApi() {
|
||||
override var name = "Okru"
|
||||
override var mainUrl = "http://ok.ru"
|
||||
override val requiresReferer = false
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||
val doc = app.get(url).document
|
||||
val sources = ArrayList<ExtractorLink>()
|
||||
val datajson = doc.select("div[data-options]").attr("data-options")
|
||||
if (datajson.isNotBlank()) {
|
||||
val main = parseJson<DataOptionsJson>(datajson)
|
||||
val metadatajson = parseJson<MetadataOkru>(main.flashvars?.metadata!!)
|
||||
val servers = metadatajson.videos
|
||||
servers.forEach {
|
||||
val quality = it.name.uppercase()
|
||||
.replace("MOBILE","144p")
|
||||
.replace("LOWEST","240p")
|
||||
.replace("LOW","360p")
|
||||
.replace("SD","480p")
|
||||
.replace("HD","720p")
|
||||
.replace("FULL","1080p")
|
||||
.replace("QUAD","1440p")
|
||||
.replace("ULTRA","4k")
|
||||
val extractedurl = it.url.replace("\\\\u0026", "&")
|
||||
sources.add(ExtractorLink(
|
||||
name,
|
||||
name = this.name,
|
||||
extractedurl,
|
||||
url,
|
||||
getQualityFromName(quality),
|
||||
isM3u8 = false
|
||||
))
|
||||
}
|
||||
}
|
||||
return sources
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.SubtitleFile
|
||||
import com.lagradost.cloudstream3.apmap
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.mvvm.suspendSafeApiCall
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.extractorApis
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import org.jsoup.Jsoup
|
||||
|
||||
/**
|
||||
* overrideMainUrl is necessary for for other vidstream clones like vidembed.cc
|
||||
* If they diverge it'd be better to make them separate.
|
||||
* */
|
||||
class Pelisplus(val mainUrl: String) {
|
||||
val name: String = "Vidstream"
|
||||
|
||||
private fun getExtractorUrl(id: String): String {
|
||||
return "$mainUrl/play?id=$id"
|
||||
}
|
||||
|
||||
private fun getDownloadUrl(id: String): String {
|
||||
return "$mainUrl/download?id=$id"
|
||||
}
|
||||
|
||||
private val normalApis = arrayListOf(MultiQuality())
|
||||
|
||||
// https://gogo-stream.com/streaming.php?id=MTE3NDg5
|
||||
suspend fun getUrl(
|
||||
id: String,
|
||||
isCasting: Boolean = false,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
): Boolean {
|
||||
try {
|
||||
normalApis.apmap { api ->
|
||||
val url = api.getExtractorUrl(id)
|
||||
api.getSafeUrl(url, subtitleCallback = subtitleCallback, callback = callback)
|
||||
}
|
||||
val extractorUrl = getExtractorUrl(id)
|
||||
|
||||
/** Stolen from GogoanimeProvider.kt extractor */
|
||||
suspendSafeApiCall {
|
||||
val link = getDownloadUrl(id)
|
||||
println("Generated vidstream download link: $link")
|
||||
val page = app.get(link, referer = extractorUrl)
|
||||
|
||||
val pageDoc = Jsoup.parse(page.text)
|
||||
val qualityRegex = Regex("(\\d+)P")
|
||||
|
||||
//a[download]
|
||||
pageDoc.select(".dowload > a")?.apmap { element ->
|
||||
val href = element.attr("href") ?: return@apmap
|
||||
val qual = if (element.text()
|
||||
.contains("HDP")
|
||||
) "1080" else qualityRegex.find(element.text())?.destructured?.component1()
|
||||
.toString()
|
||||
|
||||
if (!loadExtractor(href, link, subtitleCallback, callback)) {
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
name = this.name,
|
||||
href,
|
||||
page.url,
|
||||
getQualityFromName(qual),
|
||||
element.attr("href").contains(".m3u8")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
with(app.get(extractorUrl)) {
|
||||
val document = Jsoup.parse(this.text)
|
||||
val primaryLinks = document.select("ul.list-server-items > li.linkserver")
|
||||
//val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
|
||||
|
||||
// All vidstream links passed to extractors
|
||||
primaryLinks.distinctBy { it.attr("data-video") }.forEach { element ->
|
||||
val link = element.attr("data-video")
|
||||
//val name = element.text()
|
||||
|
||||
// Matches vidstream links with extractors
|
||||
extractorApis.filter { !it.requiresReferer || !isCasting }.apmap { api ->
|
||||
if (link.startsWith(api.mainUrl)) {
|
||||
api.getSafeUrl(link, extractorUrl, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.M3u8Helper
|
||||
|
||||
|
||||
open class PlayerVoxzer : ExtractorApi() {
|
||||
override var name = "Voxzer"
|
||||
override var mainUrl = "https://player.voxzer.org"
|
||||
override val requiresReferer = false
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||
val listurl = url.replace("/view/","/list/")
|
||||
val urltext = app.get(listurl, referer = url).text
|
||||
val m3u8regex = Regex("((https:|http:)\\/\\/.*\\.m3u8)")
|
||||
val sources = mutableListOf<ExtractorLink>()
|
||||
val listm3 = m3u8regex.find(urltext)?.value
|
||||
if (listm3?.contains("m3u8") == true)
|
||||
M3u8Helper.generateM3u8(
|
||||
name,
|
||||
listm3,
|
||||
url,
|
||||
headers = app.get(url).headers.toMap()
|
||||
).forEach { link ->
|
||||
sources.add(link)
|
||||
}
|
||||
return sources
|
||||
}
|
||||
}
|
|
@ -0,0 +1,86 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.APIHolder.unixTimeMS
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
import com.lagradost.cloudstream3.utils.getPostForm
|
||||
import org.jsoup.Jsoup
|
||||
|
||||
//class SBPlay1 : SBPlay() {
|
||||
// override var mainUrl = "https://sbplay1.com"
|
||||
//}
|
||||
|
||||
//class SBPlay2 : SBPlay() {
|
||||
// override var mainUrl = "https://sbplay2.com"
|
||||
//}
|
||||
|
||||
open class SBPlay : ExtractorApi() {
|
||||
override var mainUrl = "https://sbplay.one"
|
||||
override var name = "SBPlay"
|
||||
override val requiresReferer = false
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
|
||||
val response = app.get(url, referer = referer).text
|
||||
val document = Jsoup.parse(response)
|
||||
|
||||
val links = ArrayList<ExtractorLink>()
|
||||
|
||||
val tree = document.select("table > tbody > tr > td > a")
|
||||
for (item in tree) {
|
||||
val onDownload = item.attr("onclick")
|
||||
val name = "${this.name} - ${item.text()}"
|
||||
try {
|
||||
Regex("download_video\\('(.*?)','(.*?)','(.*?)'\\)").matchEntire(onDownload)?.let {
|
||||
val id = it.groupValues[1]
|
||||
val mode = it.groupValues[2]
|
||||
val hash = it.groupValues[3]
|
||||
val href = "https://sbplay.one/dl?op=download_orig&id=$id&mode=$mode&hash=$hash"
|
||||
val hrefResponse = app.get(href).text
|
||||
app.post("https://sbplay.one/?op=notifications&open=&_=$unixTimeMS", referer = href)
|
||||
val hrefDocument = Jsoup.parse(hrefResponse)
|
||||
val hrefSpan = hrefDocument.selectFirst("span > a")
|
||||
if (hrefSpan == null) {
|
||||
getPostForm(href, hrefResponse)?.let { form ->
|
||||
val postDocument = Jsoup.parse(form)
|
||||
val downloadBtn = postDocument.selectFirst("a.downloadbtn")?.attr("href")
|
||||
if (downloadBtn.isNullOrEmpty()) {
|
||||
val hrefSpan2 = postDocument.selectFirst("span > a")?.attr("href")
|
||||
if (hrefSpan2?.startsWith("https://") == true) {
|
||||
links.add(
|
||||
ExtractorLink(
|
||||
this.name, name,
|
||||
hrefSpan2, "", Qualities.Unknown.value, false
|
||||
)
|
||||
)
|
||||
} else {
|
||||
// no link found!!!
|
||||
}
|
||||
} else {
|
||||
links.add(
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
name,
|
||||
downloadBtn,
|
||||
"",
|
||||
Qualities.Unknown.value,
|
||||
false
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
val link = hrefSpan.attr("href")
|
||||
links.add(ExtractorLink(this.name, name, link, "", Qualities.Unknown.value, false))
|
||||
}
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
}
|
||||
}
|
||||
|
||||
return links
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
|
||||
|
||||
class Solidfiles : ExtractorApi() {
|
||||
override val name = "Solidfiles"
|
||||
override val mainUrl = "https://www.solidfiles.com"
|
||||
override val requiresReferer = false
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
|
||||
val sources = mutableListOf<ExtractorLink>()
|
||||
with(app.get(url).document) {
|
||||
this.select("script").map { script ->
|
||||
if (script.data().contains("\"streamUrl\":")) {
|
||||
val data = script.data().substringAfter("constant('viewerOptions', {").substringBefore("});")
|
||||
val source = tryParseJson<ResponseSource>("{$data}")
|
||||
val quality = Regex("\\d{3,4}p").find(source!!.nodeName)?.groupValues?.get(0)
|
||||
sources.add(
|
||||
ExtractorLink(
|
||||
name,
|
||||
name,
|
||||
source.streamUrl,
|
||||
referer = url,
|
||||
quality = getQualityFromName(quality)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return sources
|
||||
}
|
||||
|
||||
|
||||
private data class ResponseSource(
|
||||
@JsonProperty("streamUrl") val streamUrl: String,
|
||||
@JsonProperty("nodeName") val nodeName: String
|
||||
)
|
||||
|
||||
}
|
|
@ -0,0 +1,38 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.M3u8Helper
|
||||
|
||||
class SpeedoStream : ExtractorApi() {
|
||||
override val name = "SpeedoStream"
|
||||
override val mainUrl = "https://speedostream.com"
|
||||
override val requiresReferer = true
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
|
||||
val sources = mutableListOf<ExtractorLink>()
|
||||
app.get(url, referer = referer).document.select("script").map { script ->
|
||||
if (script.data().contains("jwplayer(\"vplayer\").setup(")) {
|
||||
val data = script.data().substringAfter("sources: [")
|
||||
.substringBefore("],").replace("file", "\"file\"").trim()
|
||||
tryParseJson<File>(data)?.let {
|
||||
M3u8Helper.generateM3u8(
|
||||
name,
|
||||
it.file,
|
||||
"$mainUrl/",
|
||||
).forEach { m3uData -> sources.add(m3uData) }
|
||||
}
|
||||
}
|
||||
}
|
||||
return sources
|
||||
}
|
||||
|
||||
private data class File(
|
||||
@JsonProperty("file") val file: String,
|
||||
)
|
||||
|
||||
|
||||
}
|
|
@ -0,0 +1,126 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.app
|
||||
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
|
||||
|
||||
class Ssbstream : StreamSB() {
|
||||
override var mainUrl = "https://ssbstream.net"
|
||||
}
|
||||
|
||||
class SBfull : StreamSB() {
|
||||
override var mainUrl = "https://sbfull.com"
|
||||
}
|
||||
|
||||
class StreamSB1 : StreamSB() {
|
||||
override var mainUrl = "https://sbplay1.com"
|
||||
}
|
||||
|
||||
class StreamSB2 : StreamSB() {
|
||||
override var mainUrl = "https://sbplay2.com"
|
||||
}
|
||||
|
||||
class StreamSB3 : StreamSB() {
|
||||
override var mainUrl = "https://sbplay3.com"
|
||||
}
|
||||
|
||||
class StreamSB4 : StreamSB() {
|
||||
override var mainUrl = "https://cloudemb.com"
|
||||
}
|
||||
|
||||
class StreamSB5 : StreamSB() {
|
||||
override var mainUrl = "https://sbplay.org"
|
||||
}
|
||||
|
||||
class StreamSB6 : StreamSB() {
|
||||
override var mainUrl = "https://embedsb.com"
|
||||
}
|
||||
|
||||
class StreamSB7 : StreamSB() {
|
||||
override var mainUrl = "https://pelistop.co"
|
||||
}
|
||||
|
||||
class StreamSB8 : StreamSB() {
|
||||
override var mainUrl = "https://streamsb.net"
|
||||
}
|
||||
|
||||
class StreamSB9 : StreamSB() {
|
||||
override var mainUrl = "https://sbplay.one"
|
||||
}
|
||||
|
||||
class StreamSB10 : StreamSB() {
|
||||
override var mainUrl = "https://sbplay2.xyz"
|
||||
}
|
||||
|
||||
// This is a modified version of https://github.com/jmir1/aniyomi-extensions/blob/master/src/en/genoanime/src/eu/kanade/tachiyomi/animeextension/en/genoanime/extractors/StreamSBExtractor.kt
|
||||
// The following code is under the Apache License 2.0 https://github.com/jmir1/aniyomi-extensions/blob/master/LICENSE
|
||||
open class StreamSB : ExtractorApi() {
|
||||
override var name = "StreamSB"
|
||||
override var mainUrl = "https://watchsb.com"
|
||||
override val requiresReferer = false
|
||||
|
||||
private val hexArray = "0123456789ABCDEF".toCharArray()
|
||||
|
||||
private fun bytesToHex(bytes: ByteArray): String {
|
||||
val hexChars = CharArray(bytes.size * 2)
|
||||
for (j in bytes.indices) {
|
||||
val v = bytes[j].toInt() and 0xFF
|
||||
|
||||
hexChars[j * 2] = hexArray[v ushr 4]
|
||||
hexChars[j * 2 + 1] = hexArray[v and 0x0F]
|
||||
}
|
||||
return String(hexChars)
|
||||
}
|
||||
|
||||
data class Subs (
|
||||
@JsonProperty("file") val file: String,
|
||||
@JsonProperty("label") val label: String,
|
||||
)
|
||||
|
||||
data class StreamData (
|
||||
@JsonProperty("file") val file: String,
|
||||
@JsonProperty("cdn_img") val cdnImg: String,
|
||||
@JsonProperty("hash") val hash: String,
|
||||
@JsonProperty("subs") val subs: List<Subs>?,
|
||||
@JsonProperty("length") val length: String,
|
||||
@JsonProperty("id") val id: String,
|
||||
@JsonProperty("title") val title: String,
|
||||
@JsonProperty("backup") val backup: String,
|
||||
)
|
||||
|
||||
data class Main (
|
||||
@JsonProperty("stream_data") val streamData: StreamData,
|
||||
@JsonProperty("status_code") val statusCode: Int,
|
||||
)
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||
val regexID = Regex("(embed-[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+|\\/e\\/[a-zA-Z0-9]{0,8}[a-zA-Z0-9_-]+)")
|
||||
val id = regexID.findAll(url).map {
|
||||
it.value.replace(Regex("(embed-|\\/e\\/)"),"")
|
||||
}.first()
|
||||
val bytes = id.toByteArray()
|
||||
val bytesToHex = bytesToHex(bytes)
|
||||
val master = "$mainUrl/sources43/6d6144797752744a454267617c7c${bytesToHex.lowercase()}7c7c4e61755a56456f34385243727c7c73747265616d7362/6b4a33767968506e4e71374f7c7c343837323439333133333462353935333633373836643638376337633462333634663539343137373761333635313533333835333763376333393636363133393635366136323733343435323332376137633763373337343732363536313664373336327c7c504d754478413835306633797c7c73747265616d7362"
|
||||
val headers = mapOf(
|
||||
"watchsb" to "streamsb",
|
||||
)
|
||||
val urltext = app.get(master,
|
||||
headers = headers,
|
||||
allowRedirects = false
|
||||
).text
|
||||
val mapped = urltext.let { parseJson<Main>(it) }
|
||||
val testurl = app.get(mapped.streamData.file, headers = headers).text
|
||||
// val urlmain = mapped.streamData.file.substringBefore("/hls/")
|
||||
if (urltext.contains("m3u8") && testurl.contains("EXTM3U"))
|
||||
return M3u8Helper.generateM3u8(
|
||||
name,
|
||||
mapped.streamData.file,
|
||||
url,
|
||||
headers = headers
|
||||
)
|
||||
return null
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
|
||||
class StreamTape : ExtractorApi() {
|
||||
override var name = "StreamTape"
|
||||
override var mainUrl = "https://streamtape.com"
|
||||
override val requiresReferer = false
|
||||
|
||||
private val linkRegex =
|
||||
Regex("""'robotlink'\)\.innerHTML = '(.+?)'\+ \('(.+?)'\)""")
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||
with(app.get(url)) {
|
||||
linkRegex.find(this.text)?.let {
|
||||
val extractedUrl = "https:${it.groups[1]!!.value + it.groups[2]!!.value.substring(3,)}"
|
||||
return listOf(
|
||||
ExtractorLink(
|
||||
name,
|
||||
name,
|
||||
extractedUrl,
|
||||
url,
|
||||
Qualities.Unknown.value,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.JsUnpacker
|
||||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
import java.net.URI
|
||||
|
||||
class Streamhub : ExtractorApi() {
|
||||
override var mainUrl = "https://streamhub.to"
|
||||
override var name = "Streamhub"
|
||||
override val requiresReferer = false
|
||||
|
||||
override fun getExtractorUrl(id: String): String {
|
||||
return "$mainUrl/e/$id"
|
||||
}
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||
val response = app.get(url).text
|
||||
Regex("eval((.|\\n)*?)</script>").find(response)?.groupValues?.get(1)?.let { jsEval ->
|
||||
JsUnpacker("eval$jsEval").unpack()?.let { unPacked ->
|
||||
Regex("sources:\\[\\{src:\"(.*?)\"").find(unPacked)?.groupValues?.get(1)?.let { link ->
|
||||
return listOf(
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
this.name,
|
||||
link,
|
||||
referer ?: "",
|
||||
Qualities.Unknown.value,
|
||||
URI(link).path.endsWith(".m3u8")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
|
@ -0,0 +1,60 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
import com.lagradost.nicehttp.RequestBodyTypes
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
|
||||
|
||||
class Streamlare : Slmaxed() {
|
||||
override val mainUrl = "https://streamlare.com/"
|
||||
}
|
||||
|
||||
open class Slmaxed : ExtractorApi() {
|
||||
override val name = "Streamlare"
|
||||
override val mainUrl = "https://slmaxed.com/"
|
||||
override val requiresReferer = true
|
||||
|
||||
// https://slmaxed.com/e/oLvgezw3LjPzbp8E -> oLvgezw3LjPzbp8E
|
||||
val embedRegex = Regex("""/e/([^/]*)""")
|
||||
|
||||
|
||||
data class JsonResponse(
|
||||
@JsonProperty val status: String? = null,
|
||||
@JsonProperty val message: String? = null,
|
||||
@JsonProperty val type: String? = null,
|
||||
@JsonProperty val token: String? = null,
|
||||
@JsonProperty val result: Map<String, Result>? = null
|
||||
)
|
||||
|
||||
data class Result(
|
||||
@JsonProperty val label: String? = null,
|
||||
@JsonProperty val file: String? = null,
|
||||
@JsonProperty val type: String? = null
|
||||
)
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||
val id = embedRegex.find(url)!!.groupValues[1]
|
||||
val json = app.post(
|
||||
"${mainUrl}api/video/stream/get",
|
||||
requestBody = """{"id":"$id"}""".toRequestBody(RequestBodyTypes.JSON.toMediaTypeOrNull())
|
||||
).parsed<JsonResponse>()
|
||||
return json.result?.mapNotNull {
|
||||
it.value.let { result ->
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
this.name,
|
||||
result.file ?: return@mapNotNull null,
|
||||
url,
|
||||
result.label?.replace("p", "", ignoreCase = true)?.trim()?.toIntOrNull()
|
||||
?: Qualities.Unknown.value,
|
||||
isM3u8 = result.type?.contains("hls", ignoreCase = true) == true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
||||
|
||||
data class Files(
|
||||
@JsonProperty("file") val id: String,
|
||||
@JsonProperty("label") val label: String? = null,
|
||||
)
|
||||
|
||||
open class Supervideo : ExtractorApi() {
|
||||
override var name = "Supervideo"
|
||||
override var mainUrl = "https://supervideo.tv"
|
||||
override val requiresReferer = false
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||
val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
|
||||
val response = app.get(url).text
|
||||
val jstounpack = Regex("eval((.|\\n)*?)</script>").find(response)?.groups?.get(1)?.value
|
||||
val unpacjed = JsUnpacker(jstounpack).unpack()
|
||||
val extractedUrl = unpacjed?.let { Regex("""sources:((.|\n)*?)image""").find(it) }?.groups?.get(1)?.value.toString().replace("file",""""file"""").replace("label",""""label"""").substringBeforeLast(",")
|
||||
val parsedlinks = parseJson<List<Files>>(extractedUrl)
|
||||
parsedlinks.forEach { data ->
|
||||
if (data.label.isNullOrBlank()){ // mp4 links (with labels) are slow. Use only m3u8 link.
|
||||
M3u8Helper.generateM3u8(
|
||||
name,
|
||||
data.id,
|
||||
url,
|
||||
headers = mapOf("referer" to url)
|
||||
).forEach { link ->
|
||||
extractedLinksList.add(link)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return extractedLinksList
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
|
||||
open class Tantifilm : ExtractorApi() {
|
||||
override var name = "Tantifilm"
|
||||
override var mainUrl = "https://cercafilm.net"
|
||||
override val requiresReferer = false
|
||||
|
||||
data class TantifilmJsonData (
|
||||
@JsonProperty("success") val success : Boolean,
|
||||
@JsonProperty("data") val data : List<TantifilmData>,
|
||||
@JsonProperty("captions")val captions : List<String>,
|
||||
@JsonProperty("is_vr") val is_vr : Boolean
|
||||
)
|
||||
|
||||
data class TantifilmData (
|
||||
@JsonProperty("file") val file : String,
|
||||
@JsonProperty("label") val label : String,
|
||||
@JsonProperty("type") val type : String
|
||||
)
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||
val link = "$mainUrl/api/source/${url.substringAfterLast("/")}"
|
||||
val response = app.post(link).text.replace("""\""","")
|
||||
val jsonvideodata = parseJson<TantifilmJsonData>(response)
|
||||
return jsonvideodata.data.map {
|
||||
ExtractorLink(
|
||||
it.file+".${it.type}",
|
||||
this.name,
|
||||
it.file+".${it.type}",
|
||||
mainUrl,
|
||||
it.label.filter{ it.isDigit() }.toInt(),
|
||||
false
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
|
||||
class Cinestart: Tomatomatela() {
|
||||
override var name = "Cinestart"
|
||||
override var mainUrl = "https://cinestart.net"
|
||||
override val details = "vr.php?v="
|
||||
}
|
||||
|
||||
open class Tomatomatela : ExtractorApi() {
|
||||
override var name = "Tomatomatela"
|
||||
override var mainUrl = "https://tomatomatela.com"
|
||||
override val requiresReferer = false
|
||||
private data class Tomato (
|
||||
@JsonProperty("status") val status: Int,
|
||||
@JsonProperty("file") val file: String
|
||||
)
|
||||
open val details = "details.php?v="
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||
val link = url.replace("$mainUrl/embed.html#","$mainUrl/$details")
|
||||
val server = app.get(link, allowRedirects = false).text
|
||||
val json = parseJson<Tomato>(server)
|
||||
if (json.status == 200) return listOf(
|
||||
ExtractorLink(
|
||||
name,
|
||||
name,
|
||||
json.file,
|
||||
"",
|
||||
Qualities.Unknown.value,
|
||||
isM3u8 = false
|
||||
)
|
||||
)
|
||||
return null
|
||||
}
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
|
||||
class UpstreamExtractor: ExtractorApi() {
|
||||
override val name: String = "Upstream.to"
|
||||
override val mainUrl: String = "https://upstream.to"
|
||||
override val requiresReferer = true
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
|
||||
// WIP: m3u8 link fetched but sometimes not playing
|
||||
//Log.i(this.name, "Result => (no extractor) ${url}")
|
||||
val sources: MutableList<ExtractorLink> = mutableListOf()
|
||||
val doc = app.get(url, referer = referer).text
|
||||
if (doc.isNotBlank()) {
|
||||
var reg = Regex("(?<=master)(.*)(?=hls)")
|
||||
val result = reg.find(doc)?.groupValues?.map {
|
||||
it.trim('|')
|
||||
}?.toList()
|
||||
reg = Regex("(?<=\\|file\\|)(.*)(?=\\|remove\\|)")
|
||||
val domainList = reg.find(doc)?.groupValues?.get(1)?.split("|")
|
||||
var domain = when (!domainList.isNullOrEmpty()) {
|
||||
true -> {
|
||||
if (domainList.isNotEmpty()) {
|
||||
var domName = ""
|
||||
for (part in domainList) {
|
||||
domName = "${part}.${domName}"
|
||||
}
|
||||
domName.trimEnd('.')
|
||||
} else { "" }
|
||||
}
|
||||
false -> ""
|
||||
}
|
||||
//Log.i(this.name, "Result => (domain) ${domain}")
|
||||
if (domain.isEmpty()) {
|
||||
domain = "s96.upstreamcdn.co"
|
||||
//Log.i(this.name, "Result => (default domain) ${domain}")
|
||||
}
|
||||
|
||||
result?.forEach {
|
||||
val linkUrl = "https://${domain}/hls/${it}/master.m3u8"
|
||||
sources.add(
|
||||
ExtractorLink(
|
||||
name = "Upstream m3u8",
|
||||
source = this.name,
|
||||
url = linkUrl,
|
||||
quality = Qualities.Unknown.value,
|
||||
referer = referer ?: linkUrl,
|
||||
isM3u8 = true
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
return sources
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
import com.lagradost.cloudstream3.app
|
||||
|
||||
class Uqload1 : Uqload() {
|
||||
override var mainUrl = "https://uqload.com"
|
||||
}
|
||||
|
||||
open class Uqload : ExtractorApi() {
|
||||
override val name: String = "Uqload"
|
||||
override val mainUrl: String = "https://www.uqload.com"
|
||||
private val srcRegex = Regex("""sources:.\[(.*?)\]""") // would be possible to use the parse and find src attribute
|
||||
override val requiresReferer = true
|
||||
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||
val lang = url.substring(0, 2)
|
||||
val flag =
|
||||
if (lang == "vo") {
|
||||
" \uD83C\uDDEC\uD83C\uDDE7"
|
||||
}
|
||||
else if (lang == "vf"){
|
||||
" \uD83C\uDDE8\uD83C\uDDF5"
|
||||
} else {
|
||||
""
|
||||
}
|
||||
|
||||
val cleaned_url = if (lang == "ht") { // if url doesn't contain a flag and the url starts with http://
|
||||
url
|
||||
} else {
|
||||
url.substring(2, url.length)
|
||||
}
|
||||
with(app.get(cleaned_url)) { // raised error ERROR_CODE_PARSING_CONTAINER_UNSUPPORTED (3003) is due to the response: "error_nofile"
|
||||
srcRegex.find(this.text)?.groupValues?.get(1)?.replace("\"", "")?.let { link ->
|
||||
return listOf(
|
||||
ExtractorLink(
|
||||
name,
|
||||
name + flag,
|
||||
link,
|
||||
cleaned_url,
|
||||
Qualities.Unknown.value,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
import org.mozilla.javascript.Context
|
||||
import org.mozilla.javascript.EvaluatorException
|
||||
import org.mozilla.javascript.Scriptable
|
||||
import java.util.*
|
||||
|
||||
|
||||
open class Userload : ExtractorApi() {
|
||||
override var name = "Userload"
|
||||
override var mainUrl = "https://userload.co"
|
||||
override val requiresReferer = false
|
||||
|
||||
private fun splitInput(input: String): List<String> {
|
||||
var counter = 0
|
||||
val array = ArrayList<String>()
|
||||
var buffer = ""
|
||||
for (c in input) {
|
||||
when (c) {
|
||||
'(' -> counter++
|
||||
')' -> counter--
|
||||
else -> {}
|
||||
}
|
||||
buffer += c
|
||||
if (counter == 0) {
|
||||
if (buffer.isNotBlank() && buffer != "+")
|
||||
array.add(buffer)
|
||||
buffer = ""
|
||||
}
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
private fun evaluateMath(mathExpression : String): String {
|
||||
val rhino = Context.enter()
|
||||
rhino.initStandardObjects()
|
||||
rhino.optimizationLevel = -1
|
||||
val scope: Scriptable = rhino.initStandardObjects()
|
||||
return try {
|
||||
rhino.evaluateString(scope, "eval($mathExpression)", "JavaScript", 1, null).toString()
|
||||
}
|
||||
catch (e: EvaluatorException){
|
||||
""
|
||||
}
|
||||
}
|
||||
|
||||
private fun decodeVideoJs(text: String): List<String> {
|
||||
text.replace("""\s+|/\*.*?\*/""".toRegex(), "")
|
||||
val data = text.split("""+(゚Д゚)[゚o゚]""")[1]
|
||||
val chars = data.split("""+ (゚Д゚)[゚ε゚]+""").drop(1)
|
||||
val newchars = chars.map { char ->
|
||||
char.replace("(o゚ー゚o)", "u")
|
||||
.replace("c", "0")
|
||||
.replace("(゚Д゚)['0']", "c")
|
||||
.replace("゚Θ゚", "1")
|
||||
.replace("!+[]", "1")
|
||||
.replace("-~", "1+")
|
||||
.replace("o", "3")
|
||||
.replace("_", "3")
|
||||
.replace("゚ー゚", "4")
|
||||
.replace("(+", "(")
|
||||
}
|
||||
|
||||
val subchar = mutableListOf<String>()
|
||||
|
||||
newchars.dropLast(1).forEach { v ->
|
||||
subchar.add(splitInput(v).map { evaluateMath(it).substringBefore(".") }.toString().filter { it.isDigit() })
|
||||
}
|
||||
var txtresult = ""
|
||||
subchar.forEach{
|
||||
txtresult = txtresult.plus(Char(it.toInt(8)))
|
||||
}
|
||||
val val1 = Regex(""""morocco="((.|\\n)*?)"&mycountry="""").find(txtresult)?.groups?.get(1)?.value.toString().drop(1).dropLast(1)
|
||||
val val2 = txtresult.substringAfter("""&mycountry="+""").substringBefore(")")
|
||||
|
||||
return listOf(
|
||||
val1,
|
||||
val2
|
||||
)
|
||||
|
||||
|
||||
}
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink>? {
|
||||
|
||||
val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
|
||||
|
||||
val response = app.get(url).text
|
||||
val jsToUnpack = Regex("ext/javascript\">eval((.|\\n)*?)</script>").find(response)?.groups?.get(1)?.value
|
||||
val unpacked = JsUnpacker(jsToUnpack).unpack()
|
||||
val videoJs = app.get("$mainUrl/api/assets/userload/js/videojs.js")
|
||||
val videoJsToDecode = videoJs.text
|
||||
val values = decodeVideoJs(videoJsToDecode)
|
||||
val morocco = unpacked!!.split(";").filter { it.contains(values[0]) }[0].split("=")[1].drop(1).dropLast(1)
|
||||
val mycountry = unpacked.split(";").filter { it.contains(values[1]) }[0].split("=")[1].drop(1).dropLast(1)
|
||||
val videoLinkPage = app.post("$mainUrl/api/request/", data = mapOf(
|
||||
"morocco" to morocco,
|
||||
"mycountry" to mycountry
|
||||
))
|
||||
val videoLink = videoLinkPage.text
|
||||
val nameSource = app.get(url).document.head().selectFirst("title")!!.text()
|
||||
extractedLinksList.add(
|
||||
ExtractorLink(
|
||||
name,
|
||||
name,
|
||||
videoLink,
|
||||
mainUrl,
|
||||
getQualityFromName(nameSource),
|
||||
)
|
||||
)
|
||||
|
||||
return extractedLinksList
|
||||
}
|
||||
}
|
|
@ -0,0 +1,68 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.SubtitleFile
|
||||
import com.lagradost.cloudstream3.apmap
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.M3u8Helper
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
|
||||
class VidSrcExtractor2 : VidSrcExtractor() {
|
||||
override val mainUrl = "https://vidsrc.me/embed"
|
||||
override suspend fun getUrl(
|
||||
url: String,
|
||||
referer: String?,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
) {
|
||||
val newUrl = url.lowercase().replace(mainUrl, super.mainUrl)
|
||||
super.getUrl(newUrl, referer, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
|
||||
open class VidSrcExtractor : ExtractorApi() {
|
||||
override val name = "VidSrc"
|
||||
private val absoluteUrl = "https://v2.vidsrc.me"
|
||||
override val mainUrl = "$absoluteUrl/embed"
|
||||
override val requiresReferer = false
|
||||
|
||||
override suspend fun getUrl(
|
||||
url: String,
|
||||
referer: String?,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
) {
|
||||
val iframedoc = app.get(url).document
|
||||
|
||||
val serverslist =
|
||||
iframedoc.select("div#sources.button_content div#content div#list div").map {
|
||||
val datahash = it.attr("data-hash")
|
||||
if (datahash.isNotBlank()) {
|
||||
val links = try {
|
||||
app.get("$absoluteUrl/src/$datahash", referer = "https://source.vidsrc.me/").url
|
||||
} catch (e: Exception) {
|
||||
""
|
||||
}
|
||||
links
|
||||
} else ""
|
||||
}
|
||||
|
||||
serverslist.apmap { server ->
|
||||
val linkfixed = server.replace("https://vidsrc.xyz/", "https://embedsito.com/")
|
||||
if (linkfixed.contains("/pro")) {
|
||||
val srcresponse = app.get(server, referer = absoluteUrl).text
|
||||
val m3u8Regex = Regex("((https:|http:)//.*\\.m3u8)")
|
||||
val srcm3u8 = m3u8Regex.find(srcresponse)?.value ?: return@apmap
|
||||
M3u8Helper.generateM3u8(
|
||||
name,
|
||||
srcm3u8,
|
||||
absoluteUrl
|
||||
).forEach(callback)
|
||||
} else {
|
||||
loadExtractor(linkfixed, url, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,271 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8
|
||||
import kotlinx.coroutines.delay
|
||||
import java.math.BigInteger
|
||||
|
||||
class VideovardSX : WcoStream() {
|
||||
override var mainUrl = "https://videovard.sx"
|
||||
}
|
||||
|
||||
class VideoVard : ExtractorApi() {
|
||||
override var name = "Videovard" // Cause works for animekisa and wco
|
||||
override var mainUrl = "https://videovard.to"
|
||||
override val requiresReferer = false
|
||||
|
||||
//The following code was extracted from https://github.com/saikou-app/saikou/blob/main/app/src/main/java/ani/saikou/parsers/anime/extractors/VideoVard.kt
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
|
||||
val id = url.substringAfter("e/").substringBefore("/")
|
||||
val sources = mutableListOf<ExtractorLink>()
|
||||
val hash = app.get("$mainUrl/api/make/download/$id").parsed<HashResponse>()
|
||||
delay(11_000)
|
||||
val resm3u8 = app.post(
|
||||
"$mainUrl/api/player/setup",
|
||||
mapOf("Referer" to "$mainUrl/"),
|
||||
data = mapOf(
|
||||
"cmd" to "get_stream",
|
||||
"file_code" to id,
|
||||
"hash" to hash.hash!!
|
||||
)
|
||||
).parsed<SetupResponse>()
|
||||
val m3u8 = decode(resm3u8.src!!, resm3u8.seed)
|
||||
sources.addAll(
|
||||
generateM3u8(
|
||||
name,
|
||||
m3u8,
|
||||
mainUrl,
|
||||
headers = mapOf("Referer" to mainUrl)
|
||||
)
|
||||
)
|
||||
return sources
|
||||
}
|
||||
|
||||
companion object {
|
||||
private val big0 = 0.toBigInteger()
|
||||
private val big3 = 3.toBigInteger()
|
||||
private val big4 = 4.toBigInteger()
|
||||
private val big15 = 15.toBigInteger()
|
||||
private val big16 = 16.toBigInteger()
|
||||
private val big255 = 255.toBigInteger()
|
||||
|
||||
private fun decode(dataFile: String, seed: String): String {
|
||||
val dataSeed = replace(seed)
|
||||
val newDataSeed = binaryDigest(dataSeed)
|
||||
val newDataFile = bytes2blocks(ascii2bytes(dataFile))
|
||||
var list = listOf(1633837924, 1650680933).map { it.toBigInteger() }
|
||||
val xorList = mutableListOf<BigInteger>()
|
||||
for (i in newDataFile.indices step 2) {
|
||||
val temp = newDataFile.slice(i..i + 1)
|
||||
xorList += xorBlocks(list, tearDecode(temp, newDataSeed))
|
||||
list = temp
|
||||
}
|
||||
|
||||
val result = replace(unPad(blocks2bytes(xorList)).map { it.toInt().toChar() }.joinToString(""))
|
||||
return padLastChars(result)
|
||||
}
|
||||
|
||||
private fun binaryDigest(input: String): List<BigInteger> {
|
||||
val keys = listOf(1633837924, 1650680933, 1667523942, 1684366951).map { it.toBigInteger() }
|
||||
var list1 = keys.slice(0..1)
|
||||
var list2 = list1
|
||||
val blocks = bytes2blocks(digestPad(input))
|
||||
|
||||
for (i in blocks.indices step 4) {
|
||||
list1 = tearCode(xorBlocks(blocks.slice(i..i + 1), list1), keys).toMutableList()
|
||||
list2 = tearCode(xorBlocks(blocks.slice(i + 2..i + 3), list2), keys).toMutableList()
|
||||
|
||||
val temp = list1[0]
|
||||
list1[0] = list1[1]
|
||||
list1[1] = list2[0]
|
||||
list2[0] = list2[1]
|
||||
list2[1] = temp
|
||||
}
|
||||
|
||||
return listOf(list1[0], list1[1], list2[0], list2[1])
|
||||
}
|
||||
|
||||
private fun tearDecode(a90: List<BigInteger>, a91: List<BigInteger>): MutableList<BigInteger> {
|
||||
var (a95, a96) = a90
|
||||
|
||||
var a97 = (-957401312).toBigInteger()
|
||||
for (_i in 0 until 32) {
|
||||
a96 -= ((((a95 shl 4) xor rShift(a95, 5)) + a95) xor (a97 + a91[rShift(a97, 11).and(3.toBigInteger()).toInt()]))
|
||||
a97 += 1640531527.toBigInteger()
|
||||
a95 -= ((((a96 shl 4) xor rShift(a96, 5)) + a96) xor (a97 + a91[a97.and(3.toBigInteger()).toInt()]))
|
||||
|
||||
}
|
||||
|
||||
return mutableListOf(a95, a96)
|
||||
}
|
||||
|
||||
private fun digestPad(string: String): List<BigInteger> {
|
||||
val empList = mutableListOf<BigInteger>()
|
||||
val length = string.length
|
||||
val extra = big15 - (length.toBigInteger() % big16)
|
||||
empList.add(extra)
|
||||
for (i in 0 until length) {
|
||||
empList.add(string[i].code.toBigInteger())
|
||||
}
|
||||
for (i in 0 until extra.toInt()) {
|
||||
empList.add(big0)
|
||||
}
|
||||
|
||||
return empList
|
||||
}
|
||||
|
||||
private fun bytes2blocks(a22: List<BigInteger>): List<BigInteger> {
|
||||
val empList = mutableListOf<BigInteger>()
|
||||
val length = a22.size
|
||||
var listIndex = 0
|
||||
|
||||
for (i in 0 until length) {
|
||||
val subIndex = i % 4
|
||||
val shiftedByte = a22[i] shl (3 - subIndex) * 8
|
||||
|
||||
if (subIndex == 0) {
|
||||
empList.add(shiftedByte)
|
||||
} else {
|
||||
empList[listIndex] = empList[listIndex] or shiftedByte
|
||||
}
|
||||
|
||||
if (subIndex == 3) listIndex += 1
|
||||
}
|
||||
|
||||
return empList
|
||||
}
|
||||
|
||||
private fun blocks2bytes(inp: List<BigInteger>): List<BigInteger> {
|
||||
val tempList = mutableListOf<BigInteger>()
|
||||
inp.indices.forEach { i ->
|
||||
tempList += (big255 and rShift(inp[i], 24))
|
||||
tempList += (big255 and rShift(inp[i], 16))
|
||||
tempList += (big255 and rShift(inp[i], 8))
|
||||
tempList += (big255 and inp[i])
|
||||
}
|
||||
return tempList
|
||||
}
|
||||
|
||||
private fun unPad(a46: List<BigInteger>): List<BigInteger> {
|
||||
val evenOdd = a46[0].toInt().mod(2)
|
||||
return (1 until (a46.size - evenOdd)).map {
|
||||
a46[it]
|
||||
}
|
||||
}
|
||||
|
||||
private fun xorBlocks(a76: List<BigInteger>, a77: List<BigInteger>): List<BigInteger> {
|
||||
return listOf(a76[0] xor a77[0], a76[1] xor a77[1])
|
||||
}
|
||||
|
||||
private fun rShift(input: BigInteger, by: Int): BigInteger {
|
||||
return (input.mod(4294967296.toBigInteger()) shr by)
|
||||
}
|
||||
|
||||
private fun tearCode(list1: List<BigInteger>, list2: List<BigInteger>): MutableList<BigInteger> {
|
||||
var a1 = list1[0]
|
||||
var a2 = list1[1]
|
||||
var temp = big0
|
||||
|
||||
for (_i in 0 until 32) {
|
||||
a1 += (a2 shl 4 xor rShift(a2, 5)) + a2 xor temp + list2[(temp and big3).toInt()]
|
||||
temp -= 1640531527.toBigInteger()
|
||||
a2 += (a1 shl 4 xor rShift(a1, 5)) + a1 xor temp + list2[(rShift(temp, 11) and big3).toInt()]
|
||||
}
|
||||
return mutableListOf(a1, a2)
|
||||
}
|
||||
|
||||
private fun ascii2bytes(input: String): List<BigInteger> {
|
||||
val abc = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"
|
||||
val abcMap = abc.mapIndexed { i, c -> c to i.toBigInteger() }.toMap()
|
||||
var index = -1
|
||||
val length = input.length
|
||||
var listIndex = 0
|
||||
val bytes = mutableListOf<BigInteger>()
|
||||
|
||||
while (true) {
|
||||
for (i in input) {
|
||||
if (abc.contains(i)) {
|
||||
index++
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
bytes.add((abcMap[input.getOrNull(index)?:return bytes]!! * big4))
|
||||
|
||||
while (true) {
|
||||
index++
|
||||
if (abc.contains(input[index])) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
var temp = abcMap[input[index]]!!
|
||||
|
||||
bytes[listIndex] = bytes[listIndex] or rShift(temp, 4)
|
||||
listIndex++
|
||||
temp = (big15.and(temp))
|
||||
|
||||
if ((temp == big0) && (index == (length - 1))) return bytes
|
||||
|
||||
bytes.add((temp * big4 * big4))
|
||||
|
||||
while (true) {
|
||||
index++
|
||||
if (index >= length) return bytes
|
||||
if (abc.contains(input[index])) break
|
||||
}
|
||||
|
||||
temp = abcMap[input[index]]!!
|
||||
bytes[listIndex] = bytes[listIndex] or rShift(temp, 2)
|
||||
listIndex++
|
||||
temp = (big3 and temp)
|
||||
if ((temp == big0) && (index == (length - 1))) {
|
||||
return bytes
|
||||
}
|
||||
bytes.add((temp shl 6))
|
||||
for (i in input) {
|
||||
index++
|
||||
if (abc.contains(input[index])) {
|
||||
break
|
||||
}
|
||||
}
|
||||
bytes[listIndex] = bytes[listIndex] or abcMap[input[index]]!!
|
||||
listIndex++
|
||||
}
|
||||
}
|
||||
|
||||
private fun replace(a: String): String {
|
||||
val map = mapOf(
|
||||
'0' to '5',
|
||||
'1' to '6',
|
||||
'2' to '7',
|
||||
'5' to '0',
|
||||
'6' to '1',
|
||||
'7' to '2'
|
||||
)
|
||||
var b = ""
|
||||
a.forEach {
|
||||
b += if (map.containsKey(it)) map[it] else it
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
private fun padLastChars(input:String):String{
|
||||
return if(input.reversed()[3].isDigit()) input
|
||||
else input.dropLast(4)
|
||||
}
|
||||
|
||||
private data class HashResponse(
|
||||
val hash: String? = null,
|
||||
val version:String? = null
|
||||
)
|
||||
|
||||
private data class SetupResponse(
|
||||
val seed: String,
|
||||
val src: String?=null,
|
||||
val link:String?=null
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.SubtitleFile
|
||||
import com.lagradost.cloudstream3.apmap
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.argamap
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.extractorApis
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
import org.jsoup.Jsoup
|
||||
|
||||
/**
|
||||
* overrideMainUrl is necessary for for other vidstream clones like vidembed.cc
|
||||
* If they diverge it'd be better to make them separate.
|
||||
* */
|
||||
class Vidstream(val mainUrl: String) {
|
||||
val name: String = "Vidstream"
|
||||
|
||||
private fun getExtractorUrl(id: String): String {
|
||||
return "$mainUrl/streaming.php?id=$id"
|
||||
}
|
||||
|
||||
private fun getDownloadUrl(id: String): String {
|
||||
return "$mainUrl/download?id=$id"
|
||||
}
|
||||
|
||||
private val normalApis = arrayListOf(MultiQuality())
|
||||
|
||||
// https://gogo-stream.com/streaming.php?id=MTE3NDg5
|
||||
suspend fun getUrl(
|
||||
id: String,
|
||||
isCasting: Boolean = false,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit,
|
||||
): Boolean {
|
||||
val extractorUrl = getExtractorUrl(id)
|
||||
argamap(
|
||||
{
|
||||
normalApis.apmap { api ->
|
||||
val url = api.getExtractorUrl(id)
|
||||
api.getSafeUrl(
|
||||
url,
|
||||
callback = callback,
|
||||
subtitleCallback = subtitleCallback
|
||||
)
|
||||
}
|
||||
}, {
|
||||
/** Stolen from GogoanimeProvider.kt extractor */
|
||||
val link = getDownloadUrl(id)
|
||||
println("Generated vidstream download link: $link")
|
||||
val page = app.get(link, referer = extractorUrl)
|
||||
|
||||
val pageDoc = Jsoup.parse(page.text)
|
||||
val qualityRegex = Regex("(\\d+)P")
|
||||
|
||||
//a[download]
|
||||
pageDoc.select(".dowload > a")?.apmap { element ->
|
||||
val href = element.attr("href") ?: return@apmap
|
||||
val qual = if (element.text()
|
||||
.contains("HDP")
|
||||
) "1080" else qualityRegex.find(element.text())?.destructured?.component1()
|
||||
.toString()
|
||||
|
||||
if (!loadExtractor(href, link, subtitleCallback, callback)) {
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
name = this.name,
|
||||
href,
|
||||
page.url,
|
||||
getQualityFromName(qual),
|
||||
element.attr("href").contains(".m3u8")
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}, {
|
||||
with(app.get(extractorUrl)) {
|
||||
val document = Jsoup.parse(this.text)
|
||||
val primaryLinks = document.select("ul.list-server-items > li.linkserver")
|
||||
//val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
|
||||
|
||||
// All vidstream links passed to extractors
|
||||
primaryLinks.distinctBy { it.attr("data-video") }.forEach { element ->
|
||||
val link = element.attr("data-video")
|
||||
//val name = element.text()
|
||||
|
||||
// Matches vidstream links with extractors
|
||||
extractorApis.filter { !it.requiresReferer || !isCasting }.apmap { api ->
|
||||
if (link.startsWith(api.mainUrl)) {
|
||||
api.getSafeUrl(link, extractorUrl, subtitleCallback, callback)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
return true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.parseJson
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
|
||||
open class VoeExtractor : ExtractorApi() {
|
||||
override val name: String = "Voe"
|
||||
override val mainUrl: String = "https://voe.sx"
|
||||
override val requiresReferer = false
|
||||
|
||||
private data class ResponseLinks(
|
||||
@JsonProperty("hls") val url: String?,
|
||||
@JsonProperty("video_height") val label: Int?
|
||||
//val type: String // Mp4
|
||||
)
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
|
||||
val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
|
||||
val doc = app.get(url).text
|
||||
if (doc.isNotBlank()) {
|
||||
val start = "const sources ="
|
||||
var src = doc.substring(doc.indexOf(start))
|
||||
src = src.substring(start.length, src.indexOf(";"))
|
||||
.replace("0,", "0")
|
||||
.trim()
|
||||
//Log.i(this.name, "Result => (src) ${src}")
|
||||
parseJson<ResponseLinks?>(src)?.let { voelink ->
|
||||
//Log.i(this.name, "Result => (voelink) ${voelink}")
|
||||
val linkUrl = voelink.url
|
||||
val linkLabel = voelink.label?.toString() ?: ""
|
||||
if (!linkUrl.isNullOrEmpty()) {
|
||||
extractedLinksList.add(
|
||||
ExtractorLink(
|
||||
name = this.name,
|
||||
source = this.name,
|
||||
url = linkUrl,
|
||||
quality = getQualityFromName(linkLabel),
|
||||
referer = url,
|
||||
isM3u8 = true
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return extractedLinksList
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.network.WebViewResolver
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.M3u8Helper.Companion.generateM3u8
|
||||
|
||||
open class WatchSB : ExtractorApi() {
|
||||
override var name = "WatchSB"
|
||||
override var mainUrl = "https://watchsb.com"
|
||||
override val requiresReferer = false
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
|
||||
val response = app.get(
|
||||
url, interceptor = WebViewResolver(
|
||||
Regex("""master\.m3u8""")
|
||||
)
|
||||
)
|
||||
|
||||
return generateM3u8(name, response.url, url, headers = response.headers.toMap())
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.ErrorLoadingException
|
||||
import com.lagradost.cloudstream3.extractors.helper.NineAnimeHelper.cipher
|
||||
import com.lagradost.cloudstream3.extractors.helper.NineAnimeHelper.encrypt
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
|
||||
class Vidstreamz : WcoStream() {
|
||||
override var mainUrl = "https://vidstreamz.online"
|
||||
}
|
||||
|
||||
class Vizcloud : WcoStream() {
|
||||
override var mainUrl = "https://vizcloud2.ru"
|
||||
}
|
||||
|
||||
class Vizcloud2 : WcoStream() {
|
||||
override var mainUrl = "https://vizcloud2.online"
|
||||
}
|
||||
|
||||
class VizcloudOnline : WcoStream() {
|
||||
override var mainUrl = "https://vizcloud.online"
|
||||
}
|
||||
|
||||
class VizcloudXyz : WcoStream() {
|
||||
override var mainUrl = "https://vizcloud.xyz"
|
||||
}
|
||||
|
||||
class VizcloudLive : WcoStream() {
|
||||
override var mainUrl = "https://vizcloud.live"
|
||||
}
|
||||
|
||||
class VizcloudInfo : WcoStream() {
|
||||
override var mainUrl = "https://vizcloud.info"
|
||||
}
|
||||
|
||||
class MwvnVizcloudInfo : WcoStream() {
|
||||
override var mainUrl = "https://mwvn.vizcloud.info"
|
||||
}
|
||||
|
||||
class VizcloudDigital : WcoStream() {
|
||||
override var mainUrl = "https://vizcloud.digital"
|
||||
}
|
||||
|
||||
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 {
|
||||
// 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()
|
||||
}
|
||||
return cipherKey!!
|
||||
}
|
||||
|
||||
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
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
|
||||
val group = regex.find(url)?.groupValues!!
|
||||
|
||||
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) }
|
||||
|
||||
val link =
|
||||
"${host}mediainfo/${dashify(id, viz.dashTable)}?key=${viz.mainKey}" //
|
||||
val response = app.get(link, referer = referer)
|
||||
|
||||
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)
|
||||
|
||||
|
||||
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"))
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,93 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.AppUtils
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
|
||||
class LayarKaca: XStreamCdn() {
|
||||
override val name: String = "LayarKaca-xxi"
|
||||
override val mainUrl: String = "https://layarkacaxxi.icu"
|
||||
}
|
||||
|
||||
class DBfilm: XStreamCdn() {
|
||||
override val name: String = "DBfilm"
|
||||
override val mainUrl: String = "https://dbfilm.bar"
|
||||
}
|
||||
|
||||
class Luxubu : XStreamCdn(){
|
||||
override val name: String = "FE"
|
||||
override val mainUrl: String = "https://www.luxubu.review"
|
||||
}
|
||||
|
||||
class FEmbed: XStreamCdn() {
|
||||
override val name: String = "FEmbed"
|
||||
override val mainUrl: String = "https://www.fembed.com"
|
||||
}
|
||||
|
||||
class Fplayer: XStreamCdn() {
|
||||
override val name: String = "Fplayer"
|
||||
override val mainUrl: String = "https://fplayer.info"
|
||||
}
|
||||
|
||||
class FeHD: XStreamCdn() {
|
||||
override val name: String = "FeHD"
|
||||
override val mainUrl: String = "https://fembed-hd.com"
|
||||
override var domainUrl: String = "fembed-hd.com"
|
||||
}
|
||||
|
||||
open class XStreamCdn : ExtractorApi() {
|
||||
override val name: String = "XStreamCdn"
|
||||
override val mainUrl: String = "https://embedsito.com"
|
||||
override val requiresReferer = false
|
||||
open var domainUrl: String = "embedsito.com"
|
||||
|
||||
private data class ResponseData(
|
||||
@JsonProperty("file") val file: String,
|
||||
@JsonProperty("label") val label: String,
|
||||
//val type: String // Mp4
|
||||
)
|
||||
|
||||
private data class ResponseJson(
|
||||
@JsonProperty("success") val success: Boolean,
|
||||
@JsonProperty("data") val data: List<ResponseData>?
|
||||
)
|
||||
|
||||
override fun getExtractorUrl(id: String): String {
|
||||
return "$domainUrl/api/source/$id"
|
||||
}
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
|
||||
val headers = mapOf(
|
||||
"Referer" to url,
|
||||
"User-Agent" to "Mozilla/5.0 (Windows NT 10.0; rv:78.0) Gecko/20100101 Firefox/78.0",
|
||||
)
|
||||
val id = url.trimEnd('/').split("/").last()
|
||||
val newUrl = "https://${domainUrl}/api/source/${id}"
|
||||
val extractedLinksList: MutableList<ExtractorLink> = mutableListOf()
|
||||
with(app.post(newUrl, headers = headers)) {
|
||||
if (this.code != 200) return listOf()
|
||||
val text = this.text
|
||||
if (text.isEmpty()) return listOf()
|
||||
if (text == """{"success":false,"data":"Video not found or has been removed"}""") return listOf()
|
||||
AppUtils.parseJson<ResponseJson?>(text)?.let {
|
||||
if (it.success && it.data != null) {
|
||||
it.data.forEach { data ->
|
||||
extractedLinksList.add(
|
||||
ExtractorLink(
|
||||
name,
|
||||
name = name,
|
||||
data.file,
|
||||
url,
|
||||
getQualityFromName(data.label),
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return extractedLinksList
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
|
||||
class YourUpload: ExtractorApi() {
|
||||
override val name = "Yourupload"
|
||||
override val mainUrl = "https://www.yourupload.com"
|
||||
override val requiresReferer = false
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
|
||||
val sources = mutableListOf<ExtractorLink>()
|
||||
with(app.get(url).document) {
|
||||
val quality = Regex("\\d{3,4}p").find(this.select("title").text())?.groupValues?.get(0)
|
||||
this.select("script").map { script ->
|
||||
if (script.data().contains("var jwplayerOptions = {")) {
|
||||
val data =
|
||||
script.data().substringAfter("var jwplayerOptions = {").substringBefore(",\n")
|
||||
val link = tryParseJson<ResponseSource>(
|
||||
"{${
|
||||
data.replace("file", "\"file\"").replace("'", "\"")
|
||||
}}"
|
||||
)
|
||||
sources.add(
|
||||
ExtractorLink(
|
||||
source = name,
|
||||
name = name,
|
||||
url = link!!.file,
|
||||
referer = url,
|
||||
quality = getQualityFromName(quality)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return sources
|
||||
}
|
||||
|
||||
private data class ResponseSource(
|
||||
@JsonProperty("file") val file: String,
|
||||
)
|
||||
|
||||
}
|
|
@ -0,0 +1,88 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.SubtitleFile
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.schemaStripRegex
|
||||
import org.schabi.newpipe.extractor.ServiceList
|
||||
import org.schabi.newpipe.extractor.services.youtube.extractors.YoutubeStreamExtractor
|
||||
import org.schabi.newpipe.extractor.services.youtube.linkHandler.YoutubeStreamLinkHandlerFactory
|
||||
import org.schabi.newpipe.extractor.stream.SubtitlesStream
|
||||
import org.schabi.newpipe.extractor.stream.VideoStream
|
||||
|
||||
class YoutubeShortLinkExtractor : YoutubeExtractor() {
|
||||
override val mainUrl = "https://youtu.be"
|
||||
|
||||
override fun getExtractorUrl(id: String): String {
|
||||
return "$mainUrl/$id"
|
||||
}
|
||||
}
|
||||
|
||||
class YoutubeMobileExtractor : YoutubeExtractor() {
|
||||
override val mainUrl = "https://m.youtube.com"
|
||||
}
|
||||
class YoutubeNoCookieExtractor : YoutubeExtractor() {
|
||||
override val mainUrl = "https://www.youtube-nocookie.com"
|
||||
}
|
||||
|
||||
open class YoutubeExtractor : ExtractorApi() {
|
||||
override val mainUrl = "https://www.youtube.com"
|
||||
override val requiresReferer = false
|
||||
override val name = "YouTube"
|
||||
|
||||
companion object {
|
||||
private var ytVideos: MutableMap<String, List<VideoStream>> = mutableMapOf()
|
||||
private var ytVideosSubtitles: MutableMap<String, List<SubtitlesStream>> = mutableMapOf()
|
||||
}
|
||||
|
||||
override fun getExtractorUrl(id: String): String {
|
||||
return "$mainUrl/watch?v=$id"
|
||||
}
|
||||
|
||||
override suspend fun getUrl(
|
||||
url: String,
|
||||
referer: String?,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
) {
|
||||
if (ytVideos[url].isNullOrEmpty()) {
|
||||
val link =
|
||||
YoutubeStreamLinkHandlerFactory.getInstance().fromUrl(
|
||||
url.replace(
|
||||
schemaStripRegex, ""
|
||||
)
|
||||
)
|
||||
|
||||
val s = object : YoutubeStreamExtractor(
|
||||
ServiceList.YouTube,
|
||||
link
|
||||
) {
|
||||
|
||||
}
|
||||
s.fetchPage()
|
||||
ytVideos[url] = s.videoStreams
|
||||
ytVideosSubtitles[url] = try {
|
||||
s.subtitlesDefault.filterNotNull()
|
||||
} catch (e: Exception) {
|
||||
logError(e)
|
||||
emptyList()
|
||||
}
|
||||
}
|
||||
ytVideos[url]?.mapNotNull {
|
||||
if (it.isVideoOnly || it.height <= 0) return@mapNotNull null
|
||||
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
this.name,
|
||||
it.url ?: return@mapNotNull null,
|
||||
"",
|
||||
it.height
|
||||
)
|
||||
}?.forEach(callback)
|
||||
ytVideosSubtitles[url]?.mapNotNull {
|
||||
SubtitleFile(it.languageTag ?: return@mapNotNull null, it.url ?: return@mapNotNull null)
|
||||
}?.forEach(subtitleCallback)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.apmap
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.M3u8Helper
|
||||
import com.lagradost.cloudstream3.utils.getAndUnpack
|
||||
|
||||
class Zplayer: ZplayerV2() {
|
||||
override var name: String = "Zplayer"
|
||||
override var mainUrl: String = "https://zplayer.live"
|
||||
}
|
||||
|
||||
class Upstream: ZplayerV2() {
|
||||
override var name: String = "Upstream" //Here 'cause works
|
||||
override var mainUrl: String = "https://upstream.to"
|
||||
}
|
||||
|
||||
class Streamhub2: ZplayerV2() {
|
||||
override var name = "Streamhub" //Here 'cause works
|
||||
override var mainUrl = "https://streamhub.to"
|
||||
}
|
||||
|
||||
open class ZplayerV2 : ExtractorApi() {
|
||||
override var name = "Zplayer V2"
|
||||
override var mainUrl = "https://v2.zplayer.live"
|
||||
override val requiresReferer = false
|
||||
|
||||
override suspend fun getUrl(url: String, referer: String?): List<ExtractorLink> {
|
||||
val doc = app.get(url).document
|
||||
val sources = mutableListOf<ExtractorLink>()
|
||||
doc.select("script").map { script ->
|
||||
if (script.data().contains("eval(function(p,a,c,k,e,d)")) {
|
||||
val testdata = getAndUnpack(script.data())
|
||||
val m3u8regex = Regex("((https:|http:)\\/\\/.*\\.m3u8)")
|
||||
m3u8regex.findAll(testdata).map {
|
||||
it.value
|
||||
}.toList().apmap { urlm3u8 ->
|
||||
if (urlm3u8.contains("m3u8")) {
|
||||
val testurl = app.get(urlm3u8, headers = mapOf("Referer" to url)).text
|
||||
if (testurl.contains("EXTM3U")) {
|
||||
M3u8Helper.generateM3u8(
|
||||
name,
|
||||
urlm3u8,
|
||||
url,
|
||||
headers = mapOf("Referer" to url)
|
||||
).forEach { link ->
|
||||
sources.add(link)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return sources
|
||||
}
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
package com.lagradost.cloudstream3.extractors.helper
|
||||
|
||||
import android.util.Log
|
||||
import com.lagradost.cloudstream3.SubtitleFile
|
||||
import com.lagradost.cloudstream3.apmap
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
|
||||
class AsianEmbedHelper {
|
||||
companion object {
|
||||
suspend fun getUrls(
|
||||
url: String,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
) {
|
||||
// Fetch links
|
||||
val doc = app.get(url).document
|
||||
val links = doc.select("div#list-server-more > ul > li.linkserver")
|
||||
if (!links.isNullOrEmpty()) {
|
||||
links.apmap {
|
||||
val datavid = it.attr("data-video") ?: ""
|
||||
//Log.i("AsianEmbed", "Result => (datavid) ${datavid}")
|
||||
if (datavid.isNotBlank()) {
|
||||
val res = loadExtractor(datavid, url, subtitleCallback, callback)
|
||||
Log.i("AsianEmbed", "Result => ($res) (datavid) $datavid")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
package com.lagradost.cloudstream3.extractors.helper
|
||||
|
||||
// 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
|
||||
object NineAnimeHelper {
|
||||
private const val nineAnimeKey =
|
||||
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
|
||||
private const val cipherKey = "kMXzgyNzT3k5dYab"
|
||||
|
||||
fun encodeVrf(text: String, mainKey: String): String {
|
||||
return encode(
|
||||
encrypt(
|
||||
cipher(mainKey, encode(text)),
|
||||
nineAnimeKey
|
||||
)//.replace("""=+$""".toRegex(), "")
|
||||
)
|
||||
}
|
||||
|
||||
fun decodeVrf(text: String, mainKey: String): String {
|
||||
return decode(cipher(mainKey, decrypt(text, nineAnimeKey)))
|
||||
}
|
||||
|
||||
fun encrypt(input: String, key: String): String {
|
||||
if (input.any { it.code > 255 }) 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
|
||||
}
|
||||
|
||||
fun cipher(key: String, text: String): String {
|
||||
val arr = IntArray(256) { it }
|
||||
|
||||
var u = 0
|
||||
var r: Int
|
||||
arr.indices.forEach {
|
||||
u = (u + arr[it] + key[it % key.length].code) % 256
|
||||
r = arr[it]
|
||||
arr[it] = arr[u]
|
||||
arr[u] = r
|
||||
}
|
||||
u = 0
|
||||
var c = 0
|
||||
|
||||
return text.indices.map { j ->
|
||||
c = (c + 1) % 256
|
||||
u = (u + arr[c]) % 256
|
||||
r = arr[c]
|
||||
arr[c] = arr[u]
|
||||
arr[u] = r
|
||||
(text[j].code xor arr[(arr[c] + arr[u]) % 256]).toChar()
|
||||
}.joinToString("")
|
||||
}
|
||||
|
||||
@Suppress("SameParameterValue")
|
||||
private fun decrypt(input: String, key: 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
|
||||
}
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
package com.lagradost.cloudstream3.extractors.helper
|
||||
|
||||
import com.lagradost.cloudstream3.SubtitleFile
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
import com.lagradost.cloudstream3.utils.loadExtractor
|
||||
|
||||
class VstreamhubHelper {
|
||||
companion object {
|
||||
private val baseUrl: String = "https://vstreamhub.com"
|
||||
private val baseName: String = "Vstreamhub"
|
||||
|
||||
suspend fun getUrls(
|
||||
url: String,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
) {
|
||||
if (url.startsWith(baseUrl)) {
|
||||
// Fetch links
|
||||
val doc = app.get(url).document.select("script")
|
||||
doc?.forEach {
|
||||
val innerText = it?.toString()
|
||||
if (!innerText.isNullOrEmpty()) {
|
||||
if (innerText.contains("file:")) {
|
||||
val startString = "file: "
|
||||
val aa = innerText.substring(innerText.indexOf(startString))
|
||||
val linkUrl =
|
||||
aa.substring(startString.length + 1, aa.indexOf("\",")).trim()
|
||||
//Log.i(baseName, "Result => (linkUrl) ${linkUrl}")
|
||||
val exlink = ExtractorLink(
|
||||
name = "$baseName m3u8",
|
||||
source = baseName,
|
||||
url = linkUrl,
|
||||
quality = Qualities.Unknown.value,
|
||||
referer = url,
|
||||
isM3u8 = true
|
||||
)
|
||||
callback.invoke(exlink)
|
||||
}
|
||||
if (innerText.contains("playerInstance")) {
|
||||
val aa =
|
||||
innerText.substring(innerText.indexOf("playerInstance.addButton"))
|
||||
val startString = "window.open(["
|
||||
val bb = aa.substring(aa.indexOf(startString))
|
||||
val datavid = bb.substring(startString.length, bb.indexOf("]"))
|
||||
.removeSurrounding("\"")
|
||||
if (datavid.isNotBlank()) {
|
||||
loadExtractor(datavid, url, subtitleCallback, callback)
|
||||
//Log.i(baseName, "Result => (datavid) ${datavid}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
package com.lagradost.cloudstream3.extractors.helper
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.AcraApplication.Companion.getKey
|
||||
import com.lagradost.cloudstream3.AcraApplication.Companion.setKey
|
||||
import com.lagradost.cloudstream3.app
|
||||
|
||||
class WcoHelper {
|
||||
companion object {
|
||||
private const val BACKUP_KEY_DATA = "github_keys_backup"
|
||||
|
||||
data class ExternalKeys(
|
||||
@JsonProperty("wco_key")
|
||||
val wcoKey: String? = null,
|
||||
@JsonProperty("wco_cipher_key")
|
||||
val wcocipher: String? = null
|
||||
)
|
||||
|
||||
data class NewExternalKeys(
|
||||
@JsonProperty("cipherKey")
|
||||
val cipherkey: String? = null,
|
||||
@JsonProperty("encryptKey")
|
||||
val encryptKey: String? = null,
|
||||
@JsonProperty("mainKey")
|
||||
val mainKey: String? = null,
|
||||
)
|
||||
|
||||
private var keys: ExternalKeys? = null
|
||||
private var newKeys: NewExternalKeys? = null
|
||||
private suspend fun getKeys() {
|
||||
keys = keys
|
||||
?: app.get("https://raw.githubusercontent.com/reduplicated/Cloudstream/master/docs/keys.json")
|
||||
.parsedSafe<ExternalKeys>()?.also { setKey(BACKUP_KEY_DATA, it) } ?: getKey(
|
||||
BACKUP_KEY_DATA
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun getWcoKey(): ExternalKeys? {
|
||||
getKeys()
|
||||
return keys
|
||||
}
|
||||
|
||||
private suspend fun getNewKeys() {
|
||||
newKeys = newKeys
|
||||
?: app.get("https://raw.githubusercontent.com/chekaslowakiya/BruhFlow/main/keys.json")
|
||||
.parsedSafe<NewExternalKeys>()?.also { setKey(BACKUP_KEY_DATA, it) } ?: getKey(
|
||||
BACKUP_KEY_DATA
|
||||
)
|
||||
}
|
||||
|
||||
suspend fun getNewWcoKey(): NewExternalKeys? {
|
||||
getNewKeys()
|
||||
return newKeys
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,23 +0,0 @@
|
|||
package com.lagradost.cloudstream3.utils
|
||||
|
||||
/*
|
||||
import android.content.Context
|
||||
import dalvik.system.PathClassLoader
|
||||
import java.io.File
|
||||
open class TestSource {
|
||||
open fun doMath(): Int {
|
||||
return 33
|
||||
}
|
||||
}
|
||||
object ExtensionManager {
|
||||
fun getSourceFromDex(context: Context, pkgName: String, file: File): TestSource? {
|
||||
val loader = PathClassLoader(file.absolutePath, context.classLoader)
|
||||
|
||||
val obj = Class.forName(pkgName, false, loader).newInstance()
|
||||
if (obj is TestSource) {
|
||||
println("MATH : ${obj.doMath()}")
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}*/
|
|
@ -6,6 +6,7 @@ import com.lagradost.cloudstream3.TvType
|
|||
import com.lagradost.cloudstream3.USER_AGENT
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.mvvm.logError
|
||||
import com.lagradost.cloudstream3.extractors.*
|
||||
import kotlinx.coroutines.delay
|
||||
import org.jsoup.Jsoup
|
||||
import kotlin.collections.MutableList
|
||||
|
@ -189,7 +190,138 @@ suspend fun loadExtractor(
|
|||
return false
|
||||
}
|
||||
|
||||
val extractorApis: MutableList<ExtractorApi> = arrayListOf()
|
||||
val extractorApis: MutableList<ExtractorApi> = arrayListOf(
|
||||
//AllProvider(),
|
||||
WcoStream(),
|
||||
Vidstreamz(),
|
||||
Vizcloud(),
|
||||
Vizcloud2(),
|
||||
VizcloudOnline(),
|
||||
VizcloudXyz(),
|
||||
VizcloudLive(),
|
||||
VizcloudInfo(),
|
||||
MwvnVizcloudInfo(),
|
||||
VizcloudDigital(),
|
||||
VizcloudCloud(),
|
||||
VizcloudSite(),
|
||||
VideoVard(),
|
||||
VideovardSX(),
|
||||
Mp4Upload(),
|
||||
StreamTape(),
|
||||
|
||||
//mixdrop extractors
|
||||
MixDropBz(),
|
||||
MixDropCh(),
|
||||
MixDropTo(),
|
||||
|
||||
MixDrop(),
|
||||
|
||||
Mcloud(),
|
||||
XStreamCdn(),
|
||||
|
||||
StreamSB(),
|
||||
StreamSB1(),
|
||||
StreamSB2(),
|
||||
StreamSB3(),
|
||||
StreamSB4(),
|
||||
StreamSB5(),
|
||||
StreamSB6(),
|
||||
StreamSB7(),
|
||||
StreamSB8(),
|
||||
StreamSB9(),
|
||||
StreamSB10(),
|
||||
SBfull(),
|
||||
// Streamhub(), cause Streamhub2() works
|
||||
Streamhub2(),
|
||||
Ssbstream(),
|
||||
|
||||
Fastream(),
|
||||
|
||||
FEmbed(),
|
||||
FeHD(),
|
||||
Fplayer(),
|
||||
DBfilm(),
|
||||
Luxubu(),
|
||||
LayarKaca(),
|
||||
// WatchSB(), 'cause StreamSB.kt works
|
||||
Uqload(),
|
||||
Uqload1(),
|
||||
Evoload(),
|
||||
Evoload1(),
|
||||
VoeExtractor(),
|
||||
// UpstreamExtractor(), GenericM3U8.kt works
|
||||
|
||||
Tomatomatela(),
|
||||
Cinestart(),
|
||||
OkRu(),
|
||||
OkRuHttps(),
|
||||
|
||||
// dood extractors
|
||||
DoodCxExtractor(),
|
||||
DoodPmExtractor(),
|
||||
DoodToExtractor(),
|
||||
DoodSoExtractor(),
|
||||
DoodLaExtractor(),
|
||||
DoodWsExtractor(),
|
||||
DoodShExtractor(),
|
||||
DoodWatchExtractor(),
|
||||
|
||||
AsianLoad(),
|
||||
|
||||
// GenericM3U8(),
|
||||
Jawcloud(),
|
||||
Zplayer(),
|
||||
ZplayerV2(),
|
||||
Upstream(),
|
||||
|
||||
Maxstream(),
|
||||
Tantifilm(),
|
||||
Userload(),
|
||||
Supervideo(),
|
||||
GuardareStream(),
|
||||
|
||||
// StreamSB.kt works
|
||||
// SBPlay(),
|
||||
// SBPlay1(),
|
||||
// SBPlay2(),
|
||||
|
||||
PlayerVoxzer(),
|
||||
|
||||
BullStream(),
|
||||
GMPlayer(),
|
||||
|
||||
Blogger(),
|
||||
Solidfiles(),
|
||||
YourUpload(),
|
||||
|
||||
Hxfile(),
|
||||
KotakAnimeid(),
|
||||
Neonime8n(),
|
||||
Neonime7n(),
|
||||
Yufiles(),
|
||||
Aico(),
|
||||
|
||||
JWPlayer(),
|
||||
Meownime(),
|
||||
DesuArcg(),
|
||||
DesuOdchan(),
|
||||
DesuOdvip(),
|
||||
DesuDrive(),
|
||||
|
||||
Filesim(),
|
||||
Linkbox(),
|
||||
Acefile(),
|
||||
SpeedoStream(),
|
||||
|
||||
YoutubeExtractor(),
|
||||
YoutubeShortLinkExtractor(),
|
||||
YoutubeMobileExtractor(),
|
||||
YoutubeNoCookieExtractor(),
|
||||
Streamlare(),
|
||||
VidSrcExtractor(),
|
||||
VidSrcExtractor2(),
|
||||
)
|
||||
|
||||
|
||||
fun getExtractorApiFromName(name: String): ExtractorApi {
|
||||
for (api in extractorApis) {
|
||||
|
|
Loading…
Reference in a new issue