forked from recloudstream/cloudstream
added extractors (#86)
This commit is contained in:
parent
abc9421fb1
commit
ae137f4a34
6 changed files with 195 additions and 20 deletions
|
@ -0,0 +1,37 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.SubtitleFile
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
import com.lagradost.cloudstream3.utils.httpsify
|
||||
|
||||
class Embedgram : ExtractorApi() {
|
||||
override val name = "Embedgram"
|
||||
override val mainUrl = "https://embedgram.com"
|
||||
override val requiresReferer = true
|
||||
|
||||
override suspend fun getUrl(
|
||||
url: String,
|
||||
referer: String?,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
) {
|
||||
val document = app.get(url, referer = referer).document
|
||||
val link = document.select("video source:last-child").attr("src")
|
||||
val quality = document.select("video source:last-child").attr("title")
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
this.name,
|
||||
httpsify(link),
|
||||
"$mainUrl/",
|
||||
getQualityFromName(quality),
|
||||
headers = mapOf(
|
||||
"Range" to "bytes=0-"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.SubtitleFile
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.ExtractorApi
|
||||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.Qualities
|
||||
|
||||
class Mvidoo : ExtractorApi() {
|
||||
override val name = "Mvidoo"
|
||||
override val mainUrl = "https://mvidoo.com"
|
||||
override val requiresReferer = true
|
||||
|
||||
private fun String.decodeHex(): String {
|
||||
require(length % 2 == 0) { "Must have an even length" }
|
||||
return String(
|
||||
chunked(2)
|
||||
.map { it.toInt(16).toByte() }
|
||||
.toByteArray()
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun getUrl(
|
||||
url: String,
|
||||
referer: String?,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
) {
|
||||
val document = app.get(url, referer = referer).text
|
||||
val data = Regex("""\{var\s*[^\s]+\s*=\s*(\[[^]]+])""").find(document)?.groupValues?.get(1)
|
||||
?.removeSurrounding("[", "]")?.replace("\"", "")?.replace("\\x", "")?.split(",")?.map { it.decodeHex() }?.reversed()?.joinToString("") ?: return
|
||||
Regex("source\\s*src=\"([^\"]+)").find(data)?.groupValues?.get(1)?.let { link ->
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
this.name,
|
||||
link,
|
||||
"$mainUrl/",
|
||||
Qualities.Unknown.value,
|
||||
headers = mapOf(
|
||||
"Range" to "bytes=0-"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty
|
||||
import com.lagradost.cloudstream3.APIHolder.getCaptchaToken
|
||||
import com.lagradost.cloudstream3.ErrorLoadingException
|
||||
import com.lagradost.cloudstream3.SubtitleFile
|
||||
import com.lagradost.cloudstream3.app
|
||||
import com.lagradost.cloudstream3.utils.*
|
||||
import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
|
||||
import java.net.URI
|
||||
|
||||
class Streamplay : ExtractorApi() {
|
||||
override val name = "Streamplay"
|
||||
override val mainUrl = "https://streamplay.to"
|
||||
override val requiresReferer = true
|
||||
|
||||
override suspend fun getUrl(
|
||||
url: String,
|
||||
referer: String?,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
) {
|
||||
val request = app.get(url, referer = referer)
|
||||
val redirectUrl = request.url
|
||||
val mainServer = URI(redirectUrl).let {
|
||||
"${it.scheme}://${it.host}"
|
||||
}
|
||||
val key = redirectUrl.substringAfter("embed-").substringBefore(".html")
|
||||
val token =
|
||||
request.document.select("script").find { it.data().contains("sitekey:") }?.data()
|
||||
?.substringAfterLast("sitekey: '")?.substringBefore("',")?.let { captchaKey ->
|
||||
getCaptchaToken(
|
||||
redirectUrl,
|
||||
captchaKey,
|
||||
referer = "$mainServer/"
|
||||
)
|
||||
} ?: throw ErrorLoadingException("can't bypass captcha")
|
||||
app.post(
|
||||
"$mainServer/player-$key-488x286.html", data = mapOf(
|
||||
"op" to "embed",
|
||||
"token" to token
|
||||
),
|
||||
referer = redirectUrl,
|
||||
headers = mapOf(
|
||||
"Accept" to "text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8",
|
||||
"Content-Type" to "application/x-www-form-urlencoded"
|
||||
)
|
||||
).document.select("script").find { script ->
|
||||
script.data().contains("eval(function(p,a,c,k,e,d)")
|
||||
}?.let {
|
||||
val data = getAndUnpack(it.data()).substringAfter("sources=[").substringBefore(",desc")
|
||||
.replace("file", "\"file\"")
|
||||
.replace("label", "\"label\"")
|
||||
tryParseJson<List<Source>>("[$data}]")?.map { res ->
|
||||
callback.invoke(
|
||||
ExtractorLink(
|
||||
this.name,
|
||||
this.name,
|
||||
res.file ?: return@map null,
|
||||
"$mainServer/",
|
||||
when (res.label) {
|
||||
"HD" -> Qualities.P720.value
|
||||
"SD" -> Qualities.P480.value
|
||||
else -> Qualities.Unknown.value
|
||||
},
|
||||
headers = mapOf(
|
||||
"Range" to "bytes=0-"
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
data class Source(
|
||||
@JsonProperty("file") val file: String? = null,
|
||||
@JsonProperty("label") val label: String? = null,
|
||||
)
|
||||
|
||||
}
|
|
@ -1,19 +1,23 @@
|
|||
package com.lagradost.cloudstream3.extractors
|
||||
|
||||
import com.lagradost.cloudstream3.SubtitleFile
|
||||
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.M3u8Helper
|
||||
|
||||
class UpstreamExtractor: ExtractorApi() {
|
||||
override val name: String = "Upstream.to"
|
||||
class UpstreamExtractor : ExtractorApi() {
|
||||
override val name: String = "Upstream"
|
||||
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
|
||||
override suspend fun getUrl(
|
||||
url: String,
|
||||
referer: String?,
|
||||
subtitleCallback: (SubtitleFile) -> Unit,
|
||||
callback: (ExtractorLink) -> Unit
|
||||
) {
|
||||
//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)")
|
||||
|
@ -30,7 +34,9 @@ class UpstreamExtractor: ExtractorApi() {
|
|||
domName = "${part}.${domName}"
|
||||
}
|
||||
domName.trimEnd('.')
|
||||
} else { "" }
|
||||
} else {
|
||||
""
|
||||
}
|
||||
}
|
||||
false -> ""
|
||||
}
|
||||
|
@ -42,18 +48,13 @@ class UpstreamExtractor: ExtractorApi() {
|
|||
|
||||
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
|
||||
)
|
||||
)
|
||||
M3u8Helper.generateM3u8(
|
||||
this.name,
|
||||
linkUrl,
|
||||
"$mainUrl/",
|
||||
headers = mapOf("Origin" to mainUrl)
|
||||
).forEach(callback)
|
||||
}
|
||||
}
|
||||
return sources
|
||||
}
|
||||
}
|
|
@ -7,6 +7,11 @@ import com.lagradost.cloudstream3.utils.ExtractorApi
|
|||
import com.lagradost.cloudstream3.utils.ExtractorLink
|
||||
import com.lagradost.cloudstream3.utils.getQualityFromName
|
||||
|
||||
class FEnet: XStreamCdn() {
|
||||
override val name: String = "FEnet"
|
||||
override val mainUrl: String = "https://fembed.net"
|
||||
}
|
||||
|
||||
class Rasacintaku: XStreamCdn() {
|
||||
override val mainUrl: String = "https://rasa-cintaku-semakin-berantai.xyz"
|
||||
}
|
||||
|
|
|
@ -246,13 +246,14 @@ val extractorApis: MutableList<ExtractorApi> = arrayListOf(
|
|||
Luxubu(),
|
||||
LayarKaca(),
|
||||
Rasacintaku(),
|
||||
FEnet(),
|
||||
// WatchSB(), 'cause StreamSB.kt works
|
||||
Uqload(),
|
||||
Uqload1(),
|
||||
Evoload(),
|
||||
Evoload1(),
|
||||
VoeExtractor(),
|
||||
// UpstreamExtractor(), GenericM3U8.kt works
|
||||
UpstreamExtractor(),
|
||||
|
||||
Tomatomatela(),
|
||||
Cinestart(),
|
||||
|
@ -316,6 +317,9 @@ val extractorApis: MutableList<ExtractorApi> = arrayListOf(
|
|||
Acefile(),
|
||||
SpeedoStream(),
|
||||
Zorofile(),
|
||||
Embedgram(),
|
||||
Mvidoo(),
|
||||
Streamplay(),
|
||||
|
||||
YoutubeExtractor(),
|
||||
YoutubeShortLinkExtractor(),
|
||||
|
|
Loading…
Reference in a new issue